使用Spring-WebSockets,通过STOMP发送二进制数据是否可行?

16
我能够按照spring文档使用STOMP通过WebSockets发送和接收JSON。然而,在大数据量高速率的情况下,性能较差,因此我希望对二进制消息进行分析。

  • Spring-WebSockets 4.0
  • 在Chrome 35中运行的JavaScript客户端
  • stomp.js 1.7.1

发送

我使用SimpMessageTemplate发送消息,并使用必要的代理中继 - 参见spring文档

@Controller
public class DemoBinaryController {
   @Autowired
   private SimpMessagingtemplate template

   @Scheduled(fixedDelay = 5000)
   public void demo() throws Exception {
      GenericMessage<byte[]> message = new GenericMessage<byte[]>(new byte[]{65,66,67});
      template.send("/app/binarydemo", message);
   }
}

接收

JavaScript客户端使用stomp.js标准机制接收数据。

var subscription = client.subscribe("/app/binarydemo", new function(message) {
   console.log("RX message", typeof message.body, message.body.length);
});

收到的消息是字符串形式,控制台输出如下。我期望得到一些原始类型,比如 ArrayBuffer

RX message string  3
RX message string  3

我尝试过的事情

我知道STOMP中的T代表文本,但是Spring文档暗示至少在普通WebSockets中可以使用二进制消息,而stomp规范也指出:

STOMP基于文本,但也允许传输二进制消息。

  • 调试发送代码,它似乎一直保持为byte []
  • 在接收时调试stomp.js库。当在底层ws.onmessage回调中接收到消息时,它似乎是一个字符串(stomp-1.7.1.js中的第243行)
  • 进行大量搜索 - 这似乎是一个很少有信息的话题
  • 查看stomp.js源代码。唯一与二进制相关的引用是ws.binaryType =“arraybuffer”。

更新:我在服务器端进行了更多的调试。看起来org.springframework.web.socket.TextMessage总是在org.springframework.web.socket.messaging.StompSubProtocolHandler中使用,而不是org.springframework.web.socket.BinaryMessage。我已经提出了一个功能请求SPR-12301

message = MessageBuilder.withPayload(message.getPayload()).setHeaders(headers).build();
byte[] bytes = this.stompEncoder.encode((Message<byte[]>) message);

synchronized(session) {
    session.sendMessage(new TextMessage(new String(bytes, UTF8_CHARSET)));
}

我的问题

  • 这种技术组合可以实现吗?
  • 我是否漏掉了一些关键步骤?
  • 有没有人能够提供一个可行的示例?

你能发布Stomp帧头吗? - mjn
它是哪个消息代理? - mjn
2个回答

15

似乎在org.springframework.web.socket.messaging.StompSubProtocolHandler中总是使用org.springframework.web.socket.TextMessage而不是org.springframework.web.socket.BinaryMessage。我已经提出了一个功能请求SPR-12301,该请求已被接受。

message = MessageBuilder.withPayload(message.getPayload()).setHeaders(headers).build();
byte[] bytes = this.stompEncoder.encode((Message<byte[]>) message);

synchronized(session) {
    session.sendMessage(new TextMessage(new String(bytes, UTF8_CHARSET)));
}

更新

  • SPR-12301已在4.1.2中发布,但仅添加了接收二进制消息的支持
  • 提出SPR-12475以发送二进制消息

我们是否仍然有使用stomp通过websocket发送二进制数据的相同解决方案(不使用sockjs)? - UserBSS1
嗨@Adam (+1) - 你知道Spring是否已经添加了服务器端二进制支持吗?也就是说,服务器向HTTP客户端发送二进制数据?看起来GH问题只是被关闭了,没有任何评论/更新。我处于类似的困境中,希望(8年后!)现在已经解决了这个问题。感谢您提供的所有信息! - hotmeatballsoup

2

尝试只使用ByteArrayMessageConverter来配置您的服务器:

@Configuration
@EnableWebSocketMessageBroker
public class MyWebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {
   
   @Override
    public boolean configureMessageConverters(List<MessageConverter> messageConverters) {
        messageConverters.add(new ByteArrayMessageConverter());
        return false;
    }

}

更新

啊!我明白了。谢谢:

public TextMessage(byte[] payload) {
    super(new String(payload, UTF_8));
    this.bytes = payload;
}

根据STOMP规范的另一方面:

STOMP消息的正文必须是字符串。如果要发送和接收JSON对象,...

根据ArrayBuffer

从现有数据获取数组缓冲区

  • 从Base64字符串
  • 从本地文件

因此,我认为您别无选择,只能提供一些自定义的MessageConverter,将您的byte[]转换为Base64字符串并发送它。

在JavaScript端,您应该以某种方式解码该字符串为ArrayBuffer


谢谢您的建议。我已经尝试过了,但它并没有解决问题。我已经进行了调试,配置类已经被创建并且configureMessageConverters方法已经被调用。我尝试在ByteArrayMessageConverter.supports、convertFromInternal和convertToInternal上打断点,但是这些方法都没有被调用,即使它仍然能够发送到客户端!- 是的,我肯定处于调试模式。 - Adam
回答中添加了更多信息。 - Artem Bilan
1
STOMP规范中得知:“STOMP是基于文本的,但也允许传输二进制消息。”- 标头后面可以跟随二进制数据,在这种情况下,标头必须指定内容长度。(在github上的官方规范中未提及JSON) - mjn

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接