HTTPS环境下WSS连接失败求助(NestJS GraphQL+Docker+Nginx)
搞定WSS连接握手400错误的排查指南
碰到WebSocket握手返回400的问题,大概率是代理层没正确处理WebSocket升级请求,或者服务端/客户端的路径、配置没对齐。我给你梳理几个按优先级排序的排查步骤:
1. 先补全Nginx的WebSocket代理配置(最容易踩坑的点)
你的Nginx配置里完全没处理WebSocket的专属头和协议,这是导致握手失败的头号原因。WebSocket依赖HTTP/1.1协议,并且需要Nginx转发Upgrade和Connection头来完成握手流程。把你的location块改成这样:
location /one/of/app/ { proxy_pass http://localhost:3000/; # 强制使用HTTP/1.1,WebSocket必须依赖这个 proxy_http_version 1.1; # 转发WebSocket握手必需的头信息 proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; # 可选但推荐:延长超时时间,避免长连接被Nginx主动断开 proxy_connect_timeout 7d; proxy_send_timeout 7d; proxy_read_timeout 7d; # 转发真实客户端IP和协议(方便服务端做日志或权限校验) proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; }
改完后重启Nginx:sudo systemctl restart nginx,先测试WSS连接,不行再往下走。
2. 检查NestJS GraphQL的订阅配置
确保你的NestJS服务正确开启了WebSocket订阅支持,并且路径和代理后的请求匹配:
打开
GraphQLModule的配置,确认installSubscriptionHandlers设为true,同时配置好订阅的路径和跨域:GraphQLModule.forRoot({ // 你的其他GraphQL配置(比如autoSchemaFile、context等) installSubscriptionHandlers: true, subscriptions: { 'graphql': { path: '/graphql', // 这个路径和代理后的/one/of/app/graphql对应,服务端这边是对的 cors: { origin: 'https://mydomain.com', // 换成你的前端域名,或者设为true允许所有(生产环境不推荐) credentials: true, }, }, }, }),如果你的应用全局启用了CORS中间件,记得把WebSocket相关的头也加进去:
app.enableCors({ origin: 'https://mydomain.com', credentials: true, allowedHeaders: ['Content-Type', 'Authorization'], methods: ['GET', 'POST', 'OPTIONS'], exposedHeaders: ['Upgrade'], // 允许WebSocket升级头被前端获取 });
3. 确认React Apollo客户端的WebSocket配置
检查客户端的WebSocket链接路径和参数是否正确:
创建
WebSocketLink时,URI必须是完整的WSS路径,别写错子目录:import { WebSocketLink } from '@apollo/client/link/ws'; const wsLink = new WebSocketLink({ uri: 'wss://mydomain.com/one/of/app/graphql', options: { reconnect: true, // 断开后自动重连 // 如果服务端需要认证,在这里传递token connectionParams: { authToken: localStorage.getItem('authToken'), }, }, });确保Apollo客户端正确区分HTTP请求和WebSocket订阅,用
split方法把两种请求路由到对应的链接:import { split, HttpLink } from '@apollo/client'; import { getMainDefinition } from '@apollo/client/utilities'; const httpLink = new HttpLink({ uri: 'https://mydomain.com/one/of/app/graphql', credentials: 'include', // 如果需要带Cookie的话 }); // 根据操作类型自动切换链接 const link = split( ({ query }) => { const definition = getMainDefinition(query); return ( definition.kind === 'OperationDefinition' && definition.operation === 'subscription' ); }, wsLink, httpLink, ); const client = new ApolloClient({ link, cache: new InMemoryCache(), });
4. 额外排查小技巧
- 先测试服务端本身的WebSocket是否正常:在服务器上用
curl -i -N -H "Connection: Upgrade" -H "Upgrade: websocket" -H "Sec-WebSocket-Version: 13" -H "Sec-WebSocket-Key: test" http://localhost:3000/graphql,如果返回101状态码,说明服务端的WebSocket没问题,问题肯定在Nginx或客户端。 - 查看Nginx错误日志(
/var/log/nginx/error.log)和NestJS的服务日志,找更详细的错误提示,比如路径不匹配、跨域被拦截等。 - 确认你的SSL证书是有效的,没有配置错误(比如域名不匹配、证书过期)。
内容的提问来源于stack exchange,提问作者vicodin
相关产品推荐
相关产品推荐

