跳转到主内容
趣航编程网 - 趣学编程,启航技术之路!

WebSocket连接跨域报错怎么解决 Access-Control-Allow-Origin配置【避坑】

WebSocket跨域本质是握手阶段Origin校验,非CORS预检;403错误表明服务端拒绝升级,需Nginx透传Upgrade/Connection头、Spring Boot用HandshakeInterceptor校验Origin,且Origin值必须严格匹配。 WebSocket握手阶段被拦截,不是CORS预检问题 WebSocket 跨域 和HTTP CORS根本不是一回事:它没有OPTIONS预检,只在HTTP Upgrade握手阶段检查
Origin
头,并依赖服务端返回
HTTP 101 Switching Protocols
响应。浏览器控制台报错如
Error during WebSocket handshake: Unexpected response code: 403
,说明服务端拒绝了握手请求,而不是响应头没加对。 常见误操作包括: 给WebSocket服务硬塞
Access-Control-Allow-Origin
响应头——这无效,因为握手成功后就不是HTTP了 用Nginx转发但没开启
Upgrade
Connection
透传 Spring Cloud Gateway里配了
CorsWebFilter
却没关掉只读headers限制,直接抛
UnsupportedOperationException
Nginx反向代理WebSocket必须透传Upgrade头 如果用Nginx做入口,只加
add_header Access-Control-Allow-Origin *
完全没用。关键是要让Upgrade请求原样抵达后端服务。 必须配置以下三项(缺一不可):
proxy_http_version 1.1;
(启用HTTP/1.1,否则不支持Upgrade)
proxy_set_header Upgrade $http_upgrade;
(把客户端的
Upgrade: websocket
头传下去)
proxy_set_header Connection "upgrade";
(显式声明连接升级,不能写
$http_connection
,否则可能被覆盖成
close
) 漏掉任意一条,Nginx会按普通HTTP处理,返回200或404,导致WebSocket握手失败。 Spring Boot原生WebSocket需自定义HandshakeInterceptor Spring Boot默认不校验
Origin
,但生产环境必须校验。不能靠
@CrossOrigin
注解——它只对HTTP接口生效,对WebSocket握手无效。 正确做法是实现
HandshakeInterceptor
: PHP数据库链接类(PDO+Access) PHP数据库链接类(PDO+Access) 下载 重写
beforeHandshake
方法,从
request.getHeaders().getOrigin()
取来源 白名单比对后,调用
response.getHeaders().set("Sec-WebSocket-Origin", origin)
(部分老客户端需要) 务必返回
true
放行,返回
false
会直接拒绝握手 注意:
response.setHeader("Access-Control-Allow-Origin", "*")
在这里毫无意义,别加。 Websocat或自建服务要设custom-reply-headers 像Websocat这类轻量级WebSocket服务,没有内置CORS逻辑,必须手动注入响应头。 启动命令中必须带
--custom-reply-headers
参数: 基础可用:
websocat ws-l:0.0.0.0:8080 --custom-reply-headers "Access-Control-Allow-Origin: https://your-app.com"
若需凭证(如cookie),必须同时加
Access-Control-Allow-Credentials: true
,且Origin不能为
*
生产环境禁止用
*
通配符,必须精确匹配前端域名,否则
withCredentials: true
会失效 这个头只在握手响应里起作用,后续帧通信不走HTTP,所以不用再管其他头。 最易被忽略的一点:所有方案都要求前后端
Origin
值严格一致——https://a.com 和 https://a.com/ 结尾斜杠不同,也算跨域;localhost:3000 和 127.0.0.1:3000 也不同源。别只盯着头,先核对浏览器发出来的
Origin
到底是什么。

相关文章