Spring Boot WebSocket拦截器校验失败时前端无法获取提示信息问题
WebSocket握手Token校验失败后前端无法获取提示的解决方案
问题原因
当前代码直接写入ServerHttpResponse输出流,但未正确设置响应头、未确保流完成刷新关闭,再加上WebSocket API的浏览器安全限制,导致前端无法正常获取响应提示内容。
后端代码修正
修改beforeHandshake方法中的失败处理逻辑,改用原生HttpServletResponse构建响应,确保内容能正确发送:
@Override public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Map<String, Object> attributes) throws Exception { String token = extractToken((ServletServerHttpRequest) request); if (!validateToken(token)) { // 转换为原生HttpServletResponse处理 ServletServerHttpResponse servletResponse = (ServletServerHttpResponse) response; HttpServletResponse httpResponse = servletResponse.getServletResponse(); // 设置状态码和响应头 httpResponse.setStatus(HttpStatus.UNAUTHORIZED.value()); httpResponse.setContentType("text/plain;charset=UTF-8"); // 写入提示信息并确保输出完成 PrintWriter writer = httpResponse.getWriter(); writer.write("Token校验失败,请检查Token是否有效"); writer.flush(); writer.close(); return false; } return true; }
前端处理方案
由于浏览器WebSocket API的安全限制,onerror事件无法直接获取HTTP响应体,可通过以下两种方式处理:
方式1:先通过HTTP请求预校验Token
在建立WebSocket连接前,先发送GET请求到握手地址校验Token,通过后再创建WebSocket连接:
async function connectWebSocket(token) { try { // 预校验Token const checkResponse = await fetch(`/ws?token=${token}`, { method: 'GET' }); if (!checkResponse.ok) { const errorMsg = await checkResponse.text(); alert(errorMsg); return; } // 校验通过,建立WebSocket连接 const ws = new WebSocket(`ws://localhost:8080/ws?token=${token}`); // 后续WebSocket事件处理 ws.onopen = () => console.log('连接成功'); ws.onclose = (event) => console.log('连接关闭', event); ws.onerror = (error) => console.error('连接错误', error); } catch (err) { alert('连接失败:' + err.message); } }
方式2:根据WebSocket关闭事件状态码判断
后端返回401状态码后,前端在onclose事件中通过event.code推断错误类型(WebSocket关闭码1006/1008通常对应握手失败场景):
const ws = new WebSocket(`ws://localhost:8080/ws?token=${invalidToken}`); ws.onclose = (event) => { if (event.code === 1006 || event.code === 1008) { alert('Token校验失败,请检查Token是否有效'); } else { alert('连接关闭:' + event.reason); } }; ws.onerror = (error) => { console.error('连接错误', error); };
内容的提问来源于stack exchange,提问作者chenxin
相关产品推荐
相关产品推荐

