StompFrameHandler 没有从消息中获取有效负载

Posted

技术标签:

【中文标题】StompFrameHandler 没有从消息中获取有效负载【英文标题】:StompFrameHandler doesn't get payload from message 【发布时间】:2018-01-29 13:16:03 【问题描述】:

最后,我的 websocket 客户端连接到端点,但我无法提取消息负载。 我可以获取标头,但无法识别有效负载。

我的 WebSocket 客户端如下所示:

    WebSocketTransport webSocketTransport = new WebSocketTransport(standardWebSocketClient);
    SockJsClient sockJsClient = new SockJsClient(Arrays.asList(webSocketTransport));
    WebSocketStompClient stompClient = new WebSocketStompClient(sockJsClient);

    stompClient.setMessageConverter(new StringMessageConverter());

    StompSessionHandler sessionHandler = new MyStompSessionHandler();
    ListenableFuture<StompSession> connect = stompClient.connect(URL, sessionHandler);

        StompSession stompSession = connect.get();
        System.out.println("sessionId: " + stompSession.getSessionId());

        String path = "/queue/orders";

        stompSession.subscribe(path, new MySimpleStompFrameHandler());

单脚帧处理程序:

    private class MySimpleStompFrameHandler implements StompFrameHandler 

    @Override
    public Type getPayloadType(StompHeaders stompHeaders) 
        System.out.println("Headers " + stompHeaders.toString());
        return String.class;
    

    @Override
    public void handleFrame(StompHeaders stompHeaders, Object payload) 
        System.out.println("Msg " + payload.toString());
        completableFuture.complete(payload.toString());
    

我在终端中写入了标题,但 handleFrame 方法没有任何内容。 有什么想法吗?

编辑: 调试后我发现问题出在 DefaultStompSession 类中,它使用了我的 frameHandler 实现

    private void invokeHandler(StompFrameHandler handler, Message<byte[]> message, StompHeaders stompHeaders) 
    if (message.getPayload().length == 0) 
        handler.handleFrame(stompHeaders, null);
        return;
    
    Type type = handler.getPayloadType(stompHeaders);
    Class<?> payloadType = ResolvableType.forType(type).resolve();
    Object object = getMessageConverter().fromMessage(message, payloadType);
    if (object == null) 
        throw new MessageConversionException("No suitable converter, payloadType=" + payloadType +
                ", handlerType=" + handler.getClass());
    
    handler.handleFrame(stompHeaders, object);

问题在这一行之后Type type = handler.getPayloadType(stompHeaders); 之后没有执行任何其他操作,我的程序刚刚结束,因此甚至不执行handleFrame()。 那里有什么问题?也许从 getPayloadType 返回的类型 - 我选择字符串,因为我认为每条消息都可以呈现为字符串。

【问题讨论】:

仍在努力解决这个问题。有什么想法吗? 【参考方案1】:

我也有类似的问题。

问题是我指定了stompClient.setMessageConverter(new StringMessageConverter());,而 JSON 作为有效负载传递。

解决方案(针对我的问题):stompClient.setMessageConverter(new MappingJackson2MessageConverter());

您可以做些什么来找到解决方案:

触发异常时抛出(或记录)。对于您的情况,您应该在MyStompSessionHandler 中为以下方法添加覆盖:

 @Override
 public void handleException(StompSession session, StompCommand command, StompHeaders headers, byte[] payload, Throwable exception) 
     throw new RuntimeException("Failure in WebSocket handling", exception);
 

在调试invokeHandler 时,检查负载的内容。如果你能够执行代码,你可以通过执行new String((byte[]) message.getPayload())来做到这一点。

【讨论】:

你拯救了我的一天,我使用了这一行 new String((byte[]) message.getPayload()) 并且我能够进行自定义实现,谢谢【参考方案2】:

我明白你的意思,你需要扩展StompSessionHandlerAdapter 实现StompFrameHandler

我为你尝试了一些东西:

public class MySimpleStompFrameHandler extends StompSessionHandlerAdapter implements StompFrameHandler 

private Logger logger = LogManager.getLogger(MyStompSessionHandler.class);

@Override
public void afterConnected(StompSession session, StompHeaders connectedHeaders) 
    System.out.println("Connected");


@Override
public void handleException(StompSession session, StompCommand command, StompHeaders 
 headers, byte[] payload, Throwable exception) 
    logger.error("Got an exception", exception);


@Override
public Type getPayloadType(StompHeaders headers) 
    return <payload_type>.class;


@Override
public void handleFrame(StompHeaders headers, Object payload) 
    <payload_type> msg = (<payload_type>) payload;
    System.out.println(msg);
    logger.info("Received : " + msg);

payload_type 是您要转换流数据的用户定义类

开始了!!

【讨论】:

【参考方案3】:

我分享我的实现,希望有用。 我没有设置消息转换器,而是自定义实现了方法 handleFrame

    WebSocketClient client = new StandardWebSocketClient();
    WebSocketStompClient stompClient = new WebSocketStompClient(client);
    StompSessionHandler sessionHandler = new MyStompSessionHandler(prop);
    WebSocketHttpHeaders webSocketHttpHeaders = new WebSocketHttpHeaders();
    webSocketHttpHeaders.add("Authorization", "Bearer " + token);

    StompSession session = stompClient.connect(endpoint, webSocketHttpHeaders, sessionHandler).get();

然后处理发送的消息,在我的例子中是一个 JSON 字符串对象

    @Override
    public Type getPayloadType(StompHeaders headers) 
        return null;
    

    @Override
    public void handleFrame(StompHeaders headers, Object payload) 
        String cadena = new String((byte[]) payload);
        JsonParser parser = new JsonParser();
        JsonObject obj = parser.parse(cadena).getAsJsonObject();
        System.out.println(obj.toString());
       

【讨论】:

【参考方案4】:

需要定义MessageConverter,然后用对象类型JSON实现方法getPayloadType

SockJsClient sockJsClient = new SockJsClient(transports);
WebSocketStompClient stompClient = new WebSocketStompClient(sockJsClient);
stompClient.setMessageConverter(**new MappingJackson2MessageConverter()**);

....

public class SockJsWebsocketSubscriptionHandler implements StompFrameHandler 
    @Override
    public Type getPayloadType(StompHeaders headers) 
        return **HelloMessage.class;**
    
...

【讨论】:

以上是关于StompFrameHandler 没有从消息中获取有效负载的主要内容,如果未能解决你的问题,请参考以下文章

我在 Android Q 中获得了 IMEI 空值?

确保我在 laravel 5 中获得了正确的外键语法

为啥我们要包装 HttpServletRequest ? api 提供了一个 HttpServletRequestWrapper 但我们从包装请求中获得了啥?

错误:Route.get() 需要回调函数,但在 app.js 中获得了 [object Undefined]

如何在特定时间通过 websocket 发送消息

Java - 关闭 JFrame 窗口时的消息