Spring stomp websocket "Неполный кадр, сброс входного буфера ..." - PullRequest
0 голосов
/ 01 марта 2019

В качестве конечной точки сервера msg-push я использую websocket с пружинным штампом.Когда я использую веб-браузер для подключения к нему, браузер и сервер работают хорошо.Но недавно, когда я использую симулятор приложения Cocos для подключения к своему серверу, он всегда не может подключиться правильно.На сервере нет сообщения об ошибке и запроса от клиента.При отладке я обнаружил, что запрос соединения симулятора может быть перехвачен только перехватчиком рукопожатия, но не в ClientInboundChannelInterceptor.

После некоторых исследований я обнаружил некоторые журналы ошибок на уровне TRACE, как показано ниже:

2019-03-01 11:34:09.433  INFO [msg-push,76064c86f7a1571f,76064c86f7a1571f,true] 5300 --- [nio-9006-exec-1] c.x.m.s.i.ClientHandshakeInterceptor     : before handshake --> http://172.18.3.39:9005/stomp-ws
2019-03-01 11:34:09.456  INFO [msg-push,76064c86f7a1571f,76064c86f7a1571f,true] 5300 --- [nio-9006-exec-1] c.x.m.s.i.ClientHandshakeInterceptor     : after handshake --> websocket
2019-03-01 11:34:09.487 TRACE [msg-push,,,] 5300 --- [nio-9006-exec-1] o.s.messaging.simp.stomp.StompDecoder    : Incomplete frame, resetting input buffer...
2019-03-01 11:34:09.487 TRACE [msg-push,,,] 5300 --- [nio-9006-exec-1] o.s.w.s.m.StompSubProtocolHandler        : Incomplete STOMP frame content received in session StandardWebSocketSession[id=0, uri=/stomp-ws], bufferSize=95, bufferSizeLimit=65536.

Кажется, что есть какая-то проблема с методом декодирования класса org.spring framework.messaging.simp.stomp.StompDecoder.Код для метода выглядит следующим образом:

/**
 * Decode a single STOMP frame from the given {@code buffer} into a {@link Message}.
 */
@Nullable
private Message<byte[]> decodeMessage(ByteBuffer byteBuffer, @Nullable MultiValueMap<String, String> headers) {
    Message<byte[]> decodedMessage = null;
    skipLeadingEol(byteBuffer);

    // Explicit mark/reset access via Buffer base type for compatibility
    // with covariant return type on JDK 9's ByteBuffer...
    Buffer buffer = byteBuffer;
    buffer.mark();

    String command = readCommand(byteBuffer);
    if (command.length() > 0) {
        StompHeaderAccessor headerAccessor = null;
        byte[] payload = null;
        if (byteBuffer.remaining() > 0) {
            StompCommand stompCommand = StompCommand.valueOf(command);
            headerAccessor = StompHeaderAccessor.create(stompCommand);
            initHeaders(headerAccessor);
            readHeaders(byteBuffer, headerAccessor);
            payload = readPayload(byteBuffer, headerAccessor);
        }
        if (payload != null) {
            if (payload.length > 0) {
                StompCommand stompCommand = headerAccessor.getCommand();
                if (stompCommand != null && !stompCommand.isBodyAllowed()) {
                    throw new StompConversionException(stompCommand +
                            " shouldn't have a payload: length=" + payload.length + ", headers=" + headers);
                }
            }
            headerAccessor.updateSimpMessageHeadersFromStompHeaders();
            headerAccessor.setLeaveMutable(true);
            decodedMessage = MessageBuilder.createMessage(payload, headerAccessor.getMessageHeaders());
            if (logger.isTraceEnabled()) {
                logger.trace("Decoded " + headerAccessor.getDetailedLogMessage(payload));
            }
        }
        else {
            logger.trace("Incomplete frame, resetting input buffer...");
            if (headers != null && headerAccessor != null) {
                String name = NativeMessageHeaderAccessor.NATIVE_HEADERS;
                @SuppressWarnings("unchecked")
                MultiValueMap<String, String> map = (MultiValueMap<String, String>) headerAccessor.getHeader(name);
                if (map != null) {
                    headers.putAll(map);
                }
            }
            buffer.reset();
        }
    }
    else {
        StompHeaderAccessor headerAccessor = StompHeaderAccessor.createForHeartbeat();
        initHeaders(headerAccessor);
        headerAccessor.setLeaveMutable(true);
        decodedMessage = MessageBuilder.createMessage(HEARTBEAT_PAYLOAD, headerAccessor.getMessageHeaders());
        if (logger.isTraceEnabled()) {
            logger.trace("Decoded " + headerAccessor.getDetailedLogMessage(null));
        }
    }

    return decodedMessage;
}

мы можем видеть, если полезная нагрузка == ноль, то в журналах ошибок происходит:

logger.trace("Incomplete frame, resetting input buffer...");

Приведенная выше ситуация вызовет сообщениекадр не будет правильно обработан, полученный методом: org.springframework.web.socket.messaging.StompSubProtocolHandler.handleMessageFromClient().Поскольку код messages = decoder.decode(byteBuffer); вернет пустой список, я получил журнал Incomplete STOMP frame content ...

Часть кода выглядит следующим образом:

List<Message<byte[]>> messages;
    try {
        ByteBuffer byteBuffer;
        if (webSocketMessage instanceof TextMessage) {
            byteBuffer = ByteBuffer.wrap(((TextMessage) webSocketMessage).asBytes());
        }
        else if (webSocketMessage instanceof BinaryMessage) {
            byteBuffer = ((BinaryMessage) webSocketMessage).getPayload();
        }
        else {
            return;
        }

        BufferingStompDecoder decoder = this.decoders.get(session.getId());
        if (decoder == null) {
            throw new IllegalStateException("No decoder for session id '" + session.getId() + "'");
        }

        messages = decoder.decode(byteBuffer);
        if (messages.isEmpty()) {
            if (logger.isTraceEnabled()) {
                logger.trace("Incomplete STOMP frame content received in session " +
                        session + ", bufferSize=" + decoder.getBufferSize() +
                        ", bufferSizeLimit=" + decoder.getBufferSizeLimit() + ".");
            }
            return;
        }
    }

Я не знаю, почемуфрейм сообщения будет расшифрован до нуля, кто мне может помочь?

Дополнение:

Код клиентского подключения, подобный этому:

var client = Stomp.client("ws://172.18.3.39:9005/msgpush/stomp-ws/");

var headers = {
    login: 'mylogin',
    passcode: 'mypasscode',
};
client.connect(headers, connectCallback);

Среда разработки:

springboot 2.0.3.RELEASE

...