[英]WebSocket Closes with Protocol Error 1002
我正在實現 WebSocket 消息命令行客戶端。 我已檢查此錯誤是否與協議問題相對應。 我將ws升級到最新的7.4.1。 在后端,我使用 Spring Boot Websockets 版本為 2.3.4.RELEASE。
據說造成這種情況的兩個主要原因是數據包丟失或格式錯誤的消息。 我做了一些檢查來檢查這些,但似乎沒有一個是有效的。 我測試的消息很小,因此消息大小不應該是這種情況。 連接完全在本地主機上。 我用 3 個用戶測試解決方案,有時我會收到此錯誤,有時不會。
有人可以幫我弄清楚如何擺脫這種類型的錯誤嗎?
這是我用於客戶端發送消息的代碼:
async function test(number_of_messages, break_between_messages) {
const websocket = new WebSocket(url...)
websocket.on('message', function incoming(data) {
console.log(getMessage("Received", data))
});
websocket.on('close', function(data) {
console.log('Disconnected!!!! ' + data.toString());
});
const opened = await connection(websocket)
//Wait 5 seconds
await sleep(5_000);
if (opened) {
for (i = 0; i < number_of_messages; i++) {
for (const chatId of chatIds) {
let content = i.toString() + " from " + user;
let msg = JSON.stringify({
"chatId": chatId,
"author": user,
"content": content
})
websocket.send(msg)
let message = getMessage("Sent", msg)
console.log(message)
}
await sleep(break_between_messages);
}
} else {
console.log("ERROR on Opening Connection")
return
}
// Wait 1 minute
await sleep(60_000);
websocket.close()
}
使用后端代碼:
@Component
@ServerEndpoint(value = "/webSocket/{username}",
encoders = MessageRepresentationEncoder.class, decoders = MessageRepresentationDecoder.class)
public class MessagingSocket {
private Logger logger = LoggerFactory.getInstance();
private Session session;
private MessagingAPI messagingAPI = MessagingAPIFactory.createAPI();
private UserSocketRegistry userSocketRegistry = UserSocketRegistry.createRegistry();
private SessionUserRegistry sessionUserRegistry = SessionUserRegistry.createRegistry();
@OnOpen
public void onOpen(Session session, @PathParam("username") String username) {
this.session = session;
logger.log(LoggingType.INFO, "Started new session " + session.getId());
logger.log(LoggingType.INFO, username + " connected");
userSocketRegistry.addSessionForUser(this, username);
sessionUserRegistry.addSessionForUser(session, username);
}
@OnMessage //Allows the client to send message to the socket.
public void onMessage(MessageRepresentation messageRepresentation) {
logger.log(LoggingType.INFO, "Received " + messageRepresentation.toString());
messagingAPI.write(WriteMessage.from(UUID.fromString(messageRepresentation.chatId), messageRepresentation.author, messageRepresentation.content));
broadcastToChat(messageRepresentation);
}
private void broadcastToChat(MessageRepresentation message) {
final List<MessagingSocket> sockets = messagingAPI.getUsersConnectedToChat(UUID.fromString(message.chatId)).stream().filter(user -> userSocketRegistry.hasSocketFor(user.getName()))
.map(user -> userSocketRegistry.getSocketFor(user.getName())).collect(Collectors.toList());
logger.log(LoggingType.INFO, "Starting broadcast of " + message.content + " from " + message.author + " for " + String.join(",", messagingAPI.getUsersConnectedToChat(UUID.fromString(message.chatId)).stream().map(x -> x.getName()).collect(Collectors.toList())));
for (MessagingSocket messagingSocket : sockets) {
logger.log(LoggingType.INFO, "Broadcasting message" + message.content + " to " + messagingSocket.session.getId());
messagingSocket.sendMessage(message);
}
}
private void sendMessage(MessageRepresentation message) {
try {
this.session.getBasicRemote().sendObject(message);
} catch (IOException | EncodeException e) {
logger.log(LoggingType.ERROR, "Caught exception while sending message to Session Id: " + this.session.getId());
}
}
@OnClose
public void onClose(Session session) {
String user = sessionUserRegistry.getUserFor(session);
logger.log(LoggingType.INFO, "User " + user + " with session " + this.session.getId() + " disconnected ");
sessionUserRegistry.removeSession(session);
userSocketRegistry.removeUser(user);
}
}
和 MessageRepresentation 為:
public class MessageRepresentation {
public String chatId;
public String author;
public String content;
@Override
public String toString() {
return "MessageRepresentation{" +
"chatId='" + chatId + '\'' +
", author='" + author + '\'' +
", content='" + content + '\'' +
'}';
}
}
經過進一步調查,我得到以下異常:
java.lang.IllegalStateException: The remote endpoint was in state [TEXT_FULL_WRITING] which is an invalid state for called method
at org.apache.tomcat.websocket.WsRemoteEndpointImplBase$StateMachine.checkState(WsRemoteEndpointImplBase.java:1243)
at org.apache.tomcat.websocket.WsRemoteEndpointImplBase$StateMachine.textStart(WsRemoteEndpointImplBase.java:1205)
at org.apache.tomcat.websocket.WsRemoteEndpointImplBase.sendString(WsRemoteEndpointImplBase.java:191)
at org.apache.tomcat.websocket.WsRemoteEndpointImplBase.sendObject(WsRemoteEndpointImplBase.java:600)
at org.apache.tomcat.websocket.WsRemoteEndpointBasic.sendObject(WsRemoteEndpointBasic.java:74)
at presentation.frontend.websockets.server.MessagingSocket.sendMessage(MessagingSocket.java:64)
at presentation.frontend.websockets.server.MessagingSocket.broadcastToChat(MessagingSocket.java:57)
at presentation.frontend.websockets.server.MessagingSocket.onMessage(MessagingSocket.java:47)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)
at org.apache.tomcat.websocket.pojo.PojoMessageHandlerWholeBase.onMessage(PojoMessageHandlerWholeBase.java:80)
at org.apache.tomcat.websocket.WsFrameBase.sendMessageText(WsFrameBase.java:402)
at org.apache.tomcat.websocket.server.WsFrameServer.sendMessageText(WsFrameServer.java:119)
at org.apache.tomcat.websocket.WsFrameBase.processDataText(WsFrameBase.java:502)
at org.apache.tomcat.websocket.WsFrameBase.processData(WsFrameBase.java:301)
at org.apache.tomcat.websocket.WsFrameBase.processInputBuffer(WsFrameBase.java:133)
at org.apache.tomcat.websocket.server.WsFrameServer.onDataAvailable(WsFrameServer.java:82)
at org.apache.tomcat.websocket.server.WsFrameServer.doOnDataAvailable(WsFrameServer.java:171)
at org.apache.tomcat.websocket.server.WsFrameServer.notifyDataAvailable(WsFrameServer.java:151)
at org.apache.tomcat.websocket.server.WsHttpUpgradeHandler.upgradeDispatch(WsHttpUpgradeHandler.java:148)
at org.apache.coyote.http11.upgrade.UpgradeProcessorInternal.dispatch(UpgradeProcessorInternal.java:54)
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:59)
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:868)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1590)
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.base/java.lang.Thread.run(Thread.java:834)
java.lang.IllegalStateException:消息將不會發送,因為 WebSocket session 已關閉
我在這里可能不合時宜,但我認為這可能是由於包含無效 UTF8 或類似內容的消息。 即畸形。
如果這聽起來像它可能是簡單的修復將是編碼msg
的原因
let msg = JSON.stringify({
"chatId": chatId,
"author": user,
"content": content
})
至
let msg = unescape(encodeURIComponent(JSON.stringify({
"chatId": chatId,
"author": user,
"content": content
})));
然后在另一邊解碼...
JSON.parse(decodeURIComponent(escape( ... )))
這個解決方案涉及兩個步驟。
1:查找錯誤堆棧跟蹤
@OnError
public void onError(Session session, Throwable throwable) {
logger.log(LoggingType.ERROR, "Error for " + session.getId() + " caused by: " + throwable.getMessage());
throwable.printStackTrace();
}
2:在廣播消息中將同步的BasicRemote改為異步的AsyncRemote(這在消息數增加時很重要)
private void sendMessage(MessageRepresentation message) {
this.session.getAsyncRemote().sendObject(message);
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.