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

Next.js 14 App Router集成TRPC WebSocket订阅配置问题咨询

TRPC WebSocket 订阅在 Next.js 14 App Router 中的实现指南

一、官方示例分开 prod/dev WS 配置的原因

官方将生产和开发环境的 WS 服务器分开配置,核心是两种环境的服务器运行机制、依赖宿主服务完全不同:

  • 开发环境:Next.js 自带的 dev server 基于 webpack 热重载,无法直接集成 WebSocket 服务,因此需要单独启动一个独立的 WSS 服务器监听额外端口,和 dev server 并行运行。
  • 生产环境:Next.js 生产服务器是标准 Node.js HTTP 服务器(或部署在托管平台时使用其服务),可以将 WS 服务直接挂载到现有 HTTP 服务器上,无需单独起端口,更符合生产部署规范。
  • 额外差异:开发环境会开启调试日志、宽松的 CORS 配置(允许本地跨域),生产环境则关闭调试输出、严格配置跨域规则,分开配置能避免环境间的配置污染。

二、解决 createContext 中调用 cookies()/headers() 报错的问题

你遇到的 500 错误,本质是 WebSocket 握手请求的上下文和 Next.js HTTP 请求上下文不兼容:Next.js 的 cookies()、headers() 是专为 HTTP 请求设计的,依赖内部请求上下文对象,但 WebSocket 连接基于初始握手 HTTP 请求,无法直接调用这些内置函数。

解决方法是直接从 WebSocket 的握手请求中提取所需信息:

  1. 在 applyWSSHandler 的 createContext 中,通过 req 参数(握手阶段的 HTTP 请求对象)获取 headers 和 cookies。
  2. 手动解析 cookie(需先安装 cookie 包:npm install cookie)。

示例代码:

// src/server/trpc/wss.ts
import { applyWSSHandler } from '@trpc/server/adapters/ws';
import { parse } from 'cookie';
import { appRouter } from './router';
import { createContext } from './context';

// 整合 dev/prod 配置的统一函数
export function setupWSS(server?: any) {
  const isProduction = process.env.NODE_ENV === 'production';

  let wssHandler;
  if (isProduction) {
    // 生产环境:挂载到现有 HTTP 服务器
    wssHandler = applyWSSHandler({
      server,
      router: appRouter,
      createContext: async ({ req }) => {
        // 从握手请求中提取 headers 和 cookies
        const cookies = parse(req.headers.cookie || '');
        const headers = req.headers;

        return createContext({
          cookies,
          headers,
          // 其他上下文参数
        });
      },
    });
  } else {
    // 开发环境:启动独立 WSS 服务器
    const WebSocket = require('ws');
    const wss = new WebSocket.Server({ port: 3001 });
    wssHandler = applyWSSHandler({
      wss,
      router: appRouter,
      createContext: async ({ req }) => {
        const cookies = parse(req.headers.cookie || '');
        const headers = req.headers;

        return createContext({
          cookies,
          headers,
        });
      },
    });

    console.log('WSS server running on ws://localhost:3001');
  }

  return wssHandler;
}

同时,调整 createContext 函数为接收手动传入的参数:

// src/server/trpc/context.ts
export async function createContext(opts: {
  cookies: Record<string, string>;
  headers: Record<string, string | string[] | undefined>;
}) {
  // 直接使用传入的 cookies 和 headers
  return {
    cookies: opts.cookies,
    headers: opts.headers,
    // 其他上下文逻辑,比如用户验证
  };
}

三、高效实现 TRPC 订阅的额外建议

  • 统一配置文件:用 NODE_ENV 区分环境,把 dev/prod 的 WS 逻辑整合到单个文件中,避免代码冗余。
  • 客户端连接适配:开发环境下客户端连接独立 WS 端口(如 ws://localhost:3001),生产环境下连接同域名的 WS 路径(如 wss://your-domain.com/trpc),通过环境变量自动切换:
    // src/utils/trpc.ts
    const wsUrl = process.env.NODE_ENV === 'production' 
      ? `wss://${window.location.host}/trpc` 
      : 'ws://localhost:3001';
    
  • 错误处理:添加 WS 连接失败的重连逻辑,提升用户体验。
  • 部署注意事项:若部署到 Vercel 等 Serverless 平台,需注意部分平台仅支持 Edge Runtime 下的 WebSocket,需调整为 Edge 函数;若使用传统 Node.js 服务器(如 Express),直接挂载即可。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.27 07:40:14