我将spring stomp websocket用作msg-push服务器端点。当我使用网络浏览器连接到时,浏览器和服务器都可以正常工作。但是最近,当我使用Cocos creator的应用模拟器连接到服务器时,它始终无法正确连接。服务器上没有错误消息,客户端也没有提示。调试时,我发现模拟器的连接请求只能被握手拦截器拦截,而不能进入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;
}
我们可以看到有效载荷== null,那么错误日志就会发生:
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