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

GraphQL订阅本地正常,部署Heroku后WebSocket连接失败

解决Heroku上GraphQL订阅WebSocket连接失败的问题

看起来你本地测试订阅功能完全正常,但一部署到Heroku就卡壳了——这种情况大多是Heroku的环境特性和WebSocket的配置细节没匹配上。我帮你梳理几个关键调整点,按顺序试试:

1. 确保端口使用Heroku的动态分配端口

Heroku不会用你本地的固定端口,而是通过process.env.PORT提供动态端口。检查你的config.port是否正确读取这个环境变量:

// 可以直接在代码里修改监听端口
const port = process.env.PORT || 3000;
server.listen(port, () => { ... });

2. 修正CORS配置,允许WebSocket握手请求

WebSocket的连接握手是GET请求,并且需要Upgrade和Connection头,你当前的CORS配置有两个明显问题:

  • Express的CORS中间件没允许WebSocket所需的特殊头
  • Apollo Server的cors配置只开放了POST方法

先更新Express的CORS中间件:

api.use(function (req, res, next) {
  res.setHeader('Access-Control-Allow-Origin', '*');
  // 加入GET和OPTIONS,支持WebSocket握手预检
  res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, PUT, PATCH, DELETE');
  // 加入WebSocket需要的Upgrade、Connection头
  res.setHeader('Access-Control-Allow-Headers', 'X-Requested-With, X-HTTP-Method-Override, Content-Type, Accept, Authorization, Upgrade, Connection');
  
  // OPTIONS请求直接返回200,避免预检失败
  if (req.method === 'OPTIONS') {
    return res.sendStatus(200);
  }
  next();
});

然后修正Apollo Server的applyMiddleware配置,放开methods和头:

graphQLServer.applyMiddleware({
  app: api,
  cors: {
    origin: true,
    credentials: true,
    // 加入GET和OPTIONS
    methods: ['GET', 'POST', 'OPTIONS'],
    allowedHeaders: [
      'X-Requested-With',
      'X-HTTP-Method-Override',
      'Content-Type',
      'Accept',
      'Authorization',
      'Access-Control-Allow-Origin',
      'Upgrade', // 新增WebSocket所需头
      'Connection' // 新增WebSocket所需头
    ],
  },
  playground: {
    settings: {
      'editor.theme': 'light',
    },
  },
});

3. 避免bodyParser解析WebSocket请求

bodyParser只需要处理POST请求的body,WebSocket的握手是GET请求,不要被bodyParser干扰。把bodyParser的应用改成只针对POST路由:

// 只对POST请求解析body
api.post('*', bodyParser.urlencoded({ extended: false }));
api.post('*', bodyParser.json());

4. 显式配置Apollo Server的订阅路径

有时候Playground会因为路径匹配问题连不上,显式指定订阅路径和你的GraphQL端点完全一致:

const graphQLServer = new ApolloServer({ 
  schema, 
  uploads: false,
  subscriptions: {
    path: '/graphql', // 和你的端点路径保持一致
    onConnect: () => {
      console.log('WebSocket连接成功');
    },
  },
});

5. 检查Helmet的安全头是否拦截了WebSocket

Helmet的Content-Security-Policy可能会阻止WebSocket连接,调整配置允许wss协议:

api.use(helmet({
  dnsPrefetchControl: false,
  frameguard: false,
  ieNoOpen: false,
  contentSecurityPolicy: {
    directives: {
      defaultSrc: ["'self'"],
      // 允许你的Heroku域名的WebSocket连接
      connectSrc: ["'self'", "wss://foodesk.herokuapp.com"],
    },
  },
}));

6. 确认Procfile配置正确

确保你的Procfile指定的是web dyno,这样Heroku才会把HTTP/WebSocket请求路由过来:

web: node path/to/your/server/file.js

做完这些调整后,重新部署到Heroku,应该就能正常连接WebSocket订阅了。如果还是有问题,可以查看Heroku的日志(heroku logs --tail),看看有没有WebSocket相关的错误信息,能帮你进一步定位问题。

内容的提问来源于stack exchange,提问作者Fateh

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.09 00:37:53