【问题标题】:Spring STOMP Incomplete FrameSpring STOMP 不完整框架
【发布时间】:2018-05-02 13:45:58
【问题描述】:

我在 Spring 中使用 STOMP 创建了一个 websocket。端点在与 javascript 库一起使用时就像一个魅力但是当我使用任何简单的 websocket google chrome 扩展(即简单的 WebSocket 客户端、智能 Websocket 客户端、Web Socket 客户端)时,spring 会抛出“不完整的 STOMP 框架内容消息。潜入代码,我已经能够看到导致这种情况的原因是我无法使用这些工具中的任何一个插入空字符/u0000.我假设所有的java脚本框架都默认这样做.有人找到了解决方法吗我可以在 Spring STOMP 中使用任何 websocket 客户端吗?

stomp代码位于:https://github.com/spring-projects/spring-framework/blob/master/spring-messaging/src/main/java/org/springframework/messaging/simp/stomp/StompDecoder.java

在 [当前] 第 308-320 行存在以下代码。此方法返回 null,因为 byteBuffer.remaining 不大于内容长度(均为 0)。有一个 StompSubProtocolHandler 异常会在之后触发。我尝试查看所有处理程序和拦截器,但似乎没有一种方法可以在不重写几乎所有内容的情况下拦截此级别的内容。我只想将“\0”注入有效载荷...

if (contentLength != null && contentLength >= 0) {
        if (byteBuffer.remaining() > contentLength) {
            byte[] payload = new byte[contentLength];
            byteBuffer.get(payload);
            if (byteBuffer.get() != 0) {
                throw new StompConversionException("Frame must be terminated with a null octet");
            }
            return payload;
        }
        else {
            return null;
        }
    }

【问题讨论】:

    标签: spring spring-boot stomp spring-framework-beans


    【解决方案1】:

    我遇到了完全相同的问题,我用 Web 套接字客户端进行了测试。

    为了能够在我的本地环境中手动测试 STOMP,我已经配置了我的 Spring 上下文。这样我就不需要在客户端添加空字符。如果不存在会自动添加。

    为此,我在类 AbstractWebSocketMessageBrokerConfigurer 中添加了:

    @Override
    public void configureWebSocketTransport(WebSocketTransportRegistration registration) {
        registration.addDecoratorFactory(new WebSocketHandlerDecoratorFactory() {
            @Override
            public WebSocketHandler decorate(WebSocketHandler webSocketHandler) {
                return new EmaWebSocketHandlerDecorator(webSocketHandler);
            }
        });
    }
    

    装饰器在没有请求体时自动添加回车(例如:连接命令)。

    /**
     * Extension of the {@link WebSocketHandlerDecorator websocket handler decorator} that allows to manually test the
     * STOMP protocol.
     *
     * @author Sebastien Gerard
     */
    public class EmaWebSocketHandlerDecorator extends WebSocketHandlerDecorator {
    
        private static final Logger logger = LoggerFactory.getLogger(EmaWebSocketHandlerDecorator.class);
    
        public EmaWebSocketHandlerDecorator(WebSocketHandler webSocketHandler) {
            super(webSocketHandler);
        }
    
        @Override
        public void handleMessage(WebSocketSession session, WebSocketMessage<?> message) throws Exception {
            super.handleMessage(session, updateBodyIfNeeded(message));
        }
    
        /**
         * Updates the content of the specified message. The message is updated only if it is
         * a {@link TextMessage text message} and if does not contain the <tt>null</tt> character at the end. If
         * carriage returns are missing (when the command does not need a body) there are also added.
         */
        private WebSocketMessage<?> updateBodyIfNeeded(WebSocketMessage<?> message) {
            if (!(message instanceof TextMessage) || ((TextMessage) message).getPayload().endsWith("\u0000")) {
                return message;
            }
    
            String payload = ((TextMessage) message).getPayload();
    
            final Optional<StompCommand> stompCommand = getStompCommand(payload);
    
            if (!stompCommand.isPresent()) {
                return message;
            }
    
            if (!stompCommand.get().isBodyAllowed() && !payload.endsWith("\n\n")) {
                if (payload.endsWith("\n")) {
                    payload += "\n";
                } else {
                    payload += "\n\n";
                }
            }
    
            payload += "\u0000";
    
            return new TextMessage(payload);
        }
    
        /**
         * Returns the {@link StompCommand STOMP command} associated to the specified payload.
         */
        private Optional<StompCommand> getStompCommand(String payload) {
            final int firstCarriageReturn = payload.indexOf('\n');
    
            if (firstCarriageReturn < 0) {
                return Optional.empty();
            }
    
            try {
                return Optional.of(
                        StompCommand.valueOf(payload.substring(0, firstCarriageReturn))
                );
            } catch (IllegalArgumentException e) {
                logger.trace("Error while parsing STOMP command.", e);
    
                return Optional.empty();
            }
        }
    }
    

    现在我可以执行以下请求:

    CONNECT
    accept-version:1.2
    host:localhost
    content-length:0
    
    
    SEND
    destination:/queue/com.X.notification-subscription
    content-type:text/plain
    reply-to:/temp-queue/notification
    
    hello world :)
    

    希望这会有所帮助。

    S.

    【讨论】:

      猜你喜欢
      • 2015-08-30
      • 1970-01-01
      • 2016-10-23
      • 2023-03-25
      • 2011-06-09
      • 2017-06-12
      • 2011-11-15
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多