You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.11 08:22:52