android - Okhttp websocket 预期 HTTP 101 响应,但使用 Spring Boot 服务器时为“400”
问题描述
我正在开发一个带有 Spring Boot 服务器的 Android 应用程序。
因此,我使用 OkHttp 从我的 Android 应用程序到使用 Stomp 的 Spring Boot 服务器打开一个 WebSocket 连接。
当 WebSocket 连接因服务器中引发的某些异常而关闭并且我尝试重新连接时,Expected HTTP 101 response but was '400 '
出现错误。
出于测试目的,我在 Android 应用程序向服务器发送 SEND 帧时抛出异常。
所以这个测试是这样的
- 发送 WebSocket 升级请求
- 一旦 WebSocket 连接打开,发送 CONNECT Stomp 请求
- 然后,发送 SUBSCRIBE Stomp 请求订阅队列
- 然后,在 SEND Stomp Frame 中发送消息,然后服务器抛出异常
- 服务器将响应 ERROR Stomp 帧并关闭 WebSocket 连接。
- 我尝试通过步骤 1-3 重新连接
这是用于测试的代码。
当我第一次启动我的 Android 应用程序时,它会向服务器发送 WebSocket 请求,如下所示。我编造了 IP 地址,但在我的实际应用程序中,我使用了正确的 IP 地址。
val webSocketRequest = Request.Builder().url("199.166.1.100:8081/websocket").build()
socket = okHttpClient.newWebSocket(webSocketRequest, this)
WebSocket 请求如下所示
Request{method=GET, url=http://199.166.1.100:8081/websocket, tags={}}
然后,服务器发送以下响应并调用 onOpen() 函数,这意味着握手工作正常。
Response{protocol=http/1.1, code=101, message=, url=http://199.166.1.100:8081/websocket}
在 onOpen() 函数中,我向服务器发送 Stomp CONNECT 请求,服务器响应 CONNECTED,然后我向队列发送 SUBSCRIBE 请求。到目前为止,一切正常。
我已向 StompMessageBorker 添加了一个拦截器,以便为 SEND 请求引发异常,如下所示
public Message<?> preSend(Message<?> message, @NonNull MessageChannel channel) {
StompHeaderAccessor stompHeaderAccessor = StompHeaderAccessor.wrap(message);
StompCommand stompCommand = stompHeaderAccessor.getCommand();
if (StompCommand.SEND.equals(stompCommand))
throw new RuntimeException();
return message;
}
因此,我在 SEND Stomp 框架中发送消息,当RuntimeException
抛出该消息时,服务器会向 Android 应用程序发送 ERROR Stomp Frame 或响应,并调用 OkHttp Websocket 的 onClosing() 和 onClosed() 函数,这意味着WebSocket 连接已关闭。
这就是问题所在,在关闭 WebSocket 连接后,我尝试使用以下函数重新连接 WebSocket,并且基本上经历了相同的过程,发送 CONNECT 请求,然后发送 SUBSCRIBE 请求。
override suspend fun reconnect() {
socket?.close(1000, null)
val webSocketRequest = Request.Builder().url("199.166.1.100:8081/websocket").build()
socket = okHttpClient.newWebSocket(webSocketRequest, this)
}
但我得到Expected HTTP 101 response but was '400 '
了,甚至没有调用 onOpen() 函数,我猜握手有一些问题。
通过执行此测试,我注意到了几件事。
前三个或四个重新连接请求按预期工作,调用了 onOpen() 函数,我也可以订阅队列。但是在 3 或 4 次之后,我开始收到此错误
Expected HTTP 101 response but was '400 '
,从那时起,每个重新连接请求都会收到相同的错误。一旦我得到这个
Expected HTTP 101 response but was '400 '
,重新启动我的 Spring Boot 服务器并没有帮助,但是如果重新启动我的 Android 应用程序,那么我可以连接 Websocket。但是在通过发送引发异常的消息触发 3 或 4 次断开连接后,我最终得到了相同的错误。
大家对这个问题有什么想法吗?还是我做错了?
断开 3 次或 4 次后如何建立 WebSocket 连接?
提前致谢。
===============更新=================================
我添加了一个HandshakeInterceptor
以查看beforeHandshake()
.
显然,当我收到 101 响应时,beforeHandshake()
调用了。
Response{protocol=http/1.1, code=101, message=, url=http://199.166.1.100:8081/websocket}
但是,当我收到 400 响应时
Expected HTTP 101 response but was '400 '
beforeHandshake()
根本没有调用。为什么beforeHandshake()
甚至没有调用,因为我从 Android 向服务器发送了握手请求?
===============更新=================================
让我让事情变得更容易。
我做了以下测试
- 运行 Spring Boot 服务器
- 启动安卓应用程序。
- WebSocket 连接成功。
- 重启 Spring Boot 服务器
- WebSocket 连接已关闭
- Android发送HTTP握手以重新连接WebSocket,我得到了
Expected HTTP 101 response but was '400 '
我不确定为什么重新启动会使服务器表现不同。
解决方案
推荐阅读
- android - 如何将插图应用于带有图像的 CollapsingToolbarLayout,因此工具栏中的图像绘制在状态栏后面?
- javascript - 条件为真时打开模式 - Javascript 和引导程序
- javascript - 使用 React Navigation 隐藏基于 AsyncStorage 项的底部选项卡项
- javascript - 如何根据其他两个较早的下拉选项动态调整下拉选项?
- c++ - shared_ptr 类向量的向量初始化问题
- python - 如何确定 PyQt5 对话框是否会在屏幕外显示
- c# - DirectoryInfo 的 GetFiles 未显示目录中的实际内容
- bash - bash shell 附加到变量的挫败感
- c# - 如何在使用 Host.CreateDefaultBuilder 安装的 Web 主机中配置日志记录
- javascript - 如何在 vue.js 中对计算属性进行排序