SpringBoot+Websocket: 前端报错“WebSocket connection to ‘ws://localhost:xx/chatSever‘ failed:”解决思路

省流:在SpringSecurity的过滤链配置中放行/chatSever连接路径

1. 先介绍一下WebSocket 客户端与服务器之间的连接过程

WebSocket 连接是基于 HTTP 协议建立的。WebSocket 客户端与服务器之间的连接先通过 HTTP 协议进行“握手”,然后升级为 WebSocket 连接,之后可以进行双向数据交换。详细过程如下:

1)客户端发送一个 HTTP 请求,其中包含Upgrade: websocket和Connection: Upgrade等关键头部信息。

  • Upgrade:告知服务器,客户端希望将连接协议从 HTTP 升级为 WebSocket。
  • Connection:指示请求是要升级协议。

2)服务器收到客户端的请求后,会检查是否符合 WebSocket 协议的要求。如果符合条件,服务器会返回一个 HTTP 101 状态码,请求头中也会包含Connection: Upgrade等字段,表示协议已成功切换。

3)握手成功后,WebSocket 连接建立。此时,HTTP 协议的连接被升级为 WebSocket 协议。此后,客户端和服务器之间的通信不再使用传统的 HTTP 请求-响应模型,而是进入了双向通信模式,WebSocket 可以实时传输数据。

4)当任一方(客户端或服务器)希望结束连接时,WebSocket 协议允许发送一个 Close 帧来关闭连接。关闭的过程中,会有一方发送 Close 帧,另一方响应 Close 帧,之后双方关闭TCP连接。

2. 再说结论:

项目中使用了SpringSecurity机制对请求路径进行了身份认证和权限区分,而 Spring Security 默认的安全过滤器链会将 WebSocket 握手请求(一个通过 HTTP 升级到 WebSocket 协议的请求)当作普通的 HTTP 请求进行处理,从而阻止 WebSocket 连接的建立。

因此解决步骤如下:

在Security的过滤链配置中添加

.requestMatchers("/chatSever").permitAll()  // 放行 WebSocket 连接请求

放行WebSocket 连接请求,即可解决该bug。

如果自定义了JWT认证过滤器,也应在里面放行该请求。

3. 排查思路:

1. 使用postman向websocket服务器发送连接请求:

ws://localhost:8090/chatSever

2. 发现结果如下:

图片表明,客户端尝试连接websocket服务器,先发送了一个握手请求(HTTP协议),但服务器没有返回状态101,而是状态200。结合响应的头部信息,我们可以推断出服务器对WebSocket 握手请求处理错误,进一步可以定位到SpringSecurity。

那么,既然WebSocket 握手请求被当成了普通HTTP请求,为什么返回的不是401而是200呢?

可能是WebSocket 握手请求由于其特殊性(协议升级请求),Spring Security 不会明确触发身份验证逻辑,而是返回 `200`。(具体行为还应阅读源码)

猜你喜欢

转载自blog.csdn.net/qq_63634325/article/details/144094165
今日推荐