关于springwebsocket奇怪秒断问题的解决方法

我在给我的项目添加websocket以进行全双工通信,想要实现推送但不用反反复复的去轮询接口。上回说到我用springsecurity做了安全验证,而websocket的握手就是通过http请求进行的,自然也会经过我们security的拦截器链。所以没有token就会被拦截下来。

于是胡乱的去添加请求头失败后,我查询了一些资料,知道了应该以

new WebSocket(‘ws://localhost:8080/websocket’, [token]);
这种形式添加token到请求头中,当然了,这样添加的话,它的请求头是Sec-WebSocket-Protocol,而不是authorization或者token,所以需要在原来鉴权的位置做一个手动的判断,也方便以此对socket的token做一个专用的校验,当然这不是我想说的

我想说的是接下来我遇到的问题,我在vue这边写了ws连接,但是始终秒断,而且前端只提示断开不提示连接,后端提示了连接和断开,并且是已经修复鉴权后也同样秒断,因此我排除了携带token导致这个问题的嫌疑,于是乎我怀疑是跨域问题,尝试了无果。然后我尝试让前后端在刚连上的时候互相主动发消息,结果前端因为连不上没有任何效果,后端也没收到,但后端在发送的时候会报错,而且没有指向我的代码。

这就。。。真的迷惑了,然后我就乱猜,我想可能是因为后端或者前端对ws的实现有问题,然后我替换了多种实现无果,然后我怀疑是包冲突容器冲突,改了各种配置,都无果。结果我想起以前有人教我用在线测试工具去测试ws连接的效果,于是我就试了一下,但是鉴权通不过,于是我把这个链接放行,可以看到人家第三方的在线测试用着没有任何问题

嘶,这就说明了要么鉴权有问题,要么前端实现方式有问题,可是我已经解决了鉴权问题了,得到的结果也不是401,而是1006这个websocket的错误码。然后我不抱希望的查了很久资料,才找到了让我怀疑Sec-WebSocket-Protocol会导致这个问题的文章,而且描述中均未提到我碰到的种种现象,以至于之前查到也被我忽视了

于是乎这下有了方向瞬间豁然开朗,我有针对性的查了资料:

朋友查到的更容易理解,归纳很好,我就直接用他发的这个了

 

 

如果你遇到了 “秒断” 的问题,可能是服务端无法处理这个 token。你可以尝试以下步骤来解决问题:

确认服务端是否支持在 WebSocket 握手时使用 Sec-WebSocket-Protocol 头部发送 token,如果服务端不支持,那么你需要考虑其他的实现方式。

确认服务端是否正确处理了客户端发送的 token。你可以在客户端发送请求后检查服务端的响应头是否包含了 Sec-WebSocket-Protocol 头部,以及它的值是否与客户端发送的值相同。

如果你使用了某个 WebSocket 框架,可以查阅该框架的文档或者社区,看看是否有类似的问题,并寻求帮助。

如果你无法解决这个问题,可以考虑尝试其他的实现方式,例如将 token 放在 WebSocket URL 的查询参数中,或者将 token 放在 WebSocket 数据帧中的自定义头部中。

 

 

然后是我总结的解决方案:
在握手的时候,检测有没有sec-websocket-protocal,如果有就在响应头里添加,如果没有就没事

打个比方我用的spring websocket

 

@Configuration
@EnableWebSocket
public class WebSocketConfig extends ServerEndpointConfig.Configurator {
    @Bean
    public ServerEndpointExporter serverEndpointExporter() {
        return new ServerEndpointExporter();
    }
    public void modifyHandshake(ServerEndpointConfig sec, HandshakeRequest request, HandshakeResponse response) {

        //获取请求头
        List<String> list = request.getHeaders().get(“Sec-WebSocket-Protocol”);

        //当Sec-WebSocket-Protocol请求头不为空时,需要返回给前端相同的响应
        response.getHeaders().put(“Sec-WebSocket-Protocol”,list);

        /*
        获取请求头后的逻辑处理
        */
        super.modifyHandshake(sec, request, response);
    }
}

然后在以前写的各种websocket bean顶上的serverendpoint注解里添加configurator

@ServerEndpoint(value = “/websocket”, configurator = WebSocketConfig.class)
这样就能成功解决这个问题了

坑啊,到处都是坑,感觉这些个东西真的就很烦,又没有合适的办法可以一下子找到这个问题,gpt4给出的方案是禁用http2,我服了,没用的。