403错误源于服务端在HTTP层拒绝WebSocket升级请求,主因是Origin校验失败、Nginx未透传Upgrade/Connection头或onWebSocketConnect中硬拦截。

Workerman WebSocket 客户端收到 403 响应码,说明服务端明确拒绝了升级请求
这不是网络不通或连接超时的问题,而是服务端在 HTTP 层就拦截了 WebSocket 握手请求。浏览器控制台看到 Error during WebSocket handshake: Unexpected response code: 403,基本可以排除客户端代码写错地址或端口这类低级错误。
常见触发 403 的服务端逻辑位置
Workerman 中,403 几乎都来自自定义的握手校验逻辑,而不是框架默认行为。重点排查以下几处:
-
onWebSocketConnect回调里手动调用了$http_response->end()并传入 403 状态码 - 你在
onWebSocketConnect中检查了$http_response->header('Origin')或$_SERVER['HTTP_ORIGIN'],但没匹配到白名单域名,直接返回了 403 - 使用了 Nginx 反向代理,而 Nginx 配置中加了
deny all;或auth_basic拦截,导致 Upgrade 请求在到达 Workerman 前就被拦下 - 服务端代码里有类似
if (!in_array($origin, $allowed_origins)) { http_response_code(403); exit; }这类硬拦截
如何快速定位是哪一层返回的 403
分三步缩小范围:
- 用
curl -i -N -H "Upgrade: websocket" -H "Connection: Upgrade" -H "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==" http://127.0.0.1:8080/test直连 Workerman(绕过浏览器和 Nginx),看是否仍返回 403 —— 如果不返回,问题在 Nginx 或 HTTPS 代理层 - 临时注释掉
onWebSocketConnect中所有业务判断逻辑,只留return true;,再测试 —— 如果 403 消失,说明拦截逻辑就在这个回调里 - 检查 Nginx 配置中是否有
location /test { deny all; }、auth_request或未透传Upgrade和Connection头的 proxy 设置
容易被忽略的跨域 Origin 校验细节
Workerman 不自动校验 Origin,所有校验都是你写的。但要注意几个坑:
- 浏览器发来的
Origin头可能是http://localhost:3000、https://myapp.com,甚至空字符串(某些 WebView 场景),不能只比对完整域名 - 如果用
$_SERVER['HTTP_ORIGIN']获取,注意它可能为false或不存在,直接in_array()会出 warning 并可能逻辑失效 - 开发时用
file://协议打开 HTML,Origin 是null,很多校验逻辑会把它当非法来源直接 403 - 别在生产环境用
*通配 Origin,Workerman 的 WebSocket 握手要求 Origin 必须精确匹配或显式允许,Access-Control-Allow-Origin: *对 WebSocket 升级无效
真正卡住人的往往不是“有没有校验”,而是校验时没处理好空值、协议差异、本地开发协议特殊性这些边界情况。先关掉校验跑通流程,再逐步加回逻辑,比对着报错猜要快得多。

















