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

Next.js App Router调用gRPC接口触发500错误及headers未定义问题

问题描述

基于Next.js的App Router搭建接口服务,调用端点时返回500内部服务器错误,服务器日志报错:
error TypeError: Cannot read properties of undefined (reading 'headers') at eval (webpack-internal:///(rsc)/./node_modules/next/dist/server/future/route-modules/app-route/module.js:266:61)

调试发现调用client.Query()后立即返回500错误,未进入回调的return语句,但能看到grpcResponse已正确填充。相关实现代码如下:

import { NextRequest, NextResponse } from 'next/server';

// Import and initialize your gRPC client here
const grpc = require('@grpc/grpc-js');
const protoLoader = require('@grpc/proto-loader');

var PROTO_PATH = __dirname + '/../myproto.proto';

try {
  var packageDefinition = protoLoader.loadSync(PROTO_PATH, {
    keepCase: true,
    longs: String,
    enums: String,
    defaults: true,
    oneofs: true
  });
} catch (error) {
  console.error('Error loading proto file:', error);
}

var qProto = grpc.loadPackageDefinition(packageDefinition).myproto;

var client = new qProto.QEngine('localhost:6767', grpc.credentials.createInsecure())

export async function POST(req: Request, res: Response) {
  try {
    const body = await req.json()
    var reqq = qProto.QueryRequest;

    reqq.query_string = body.queryString
    reqq.debug = body.debug;

    // Make the gRPC query call using your gRPC client
    client.Query(reqq, function(err: Error, grpcResponse: any) {
      // console.log('gRPC Response:', JSON.stringify(grpcResponse, null, 2));
      if (err) {
        console.error('Error calling Query:', err);
        return NextResponse.json({ error: 'Internal Server Error' }, { status: 500 })
      } else {
        // Set the status code and send the response directly using res.json
        return NextResponse.json({ data: grpcResponse }, { status: 200 })
      }
    });
  } catch (error) {
    console.error('Error:', error);
    return NextResponse.json({ error: 'Internal Server Error' }, { status: 500 })
  }
}
问题原因分析
  • Next.js App Router的API路由要求async函数返回NextResponse或Promise<NextResponse>,原代码中POST函数调用client.Query后无返回值,函数直接执行完毕,Next.js无法获取有效响应对象,触发headers未定义错误。
  • client.Query是回调式异步调用,回调内返回NextResponse无意义,此时POST函数已执行结束,Next.js已开始处理响应流程。
  • gRPC请求对象创建错误:直接修改qProto.QueryRequest构造函数的属性,而非实例化请求对象,属于错误用法。
解决方法

核心修正点

  1. 将gRPC回调封装为Promise,让POST函数可以通过await等待异步操作完成,确保返回正确的NextResponse。
  2. 正确实例化gRPC请求对象,避免直接修改构造函数。
  3. 移除冗余的res参数,App Router的API路由仅需req参数,直接返回NextResponse即可。

修改后的代码

import { NextRequest, NextResponse } from 'next/server';
const grpc = require('@grpc/grpc-js');
const protoLoader = require('@grpc/proto-loader');

const PROTO_PATH = __dirname + '/../myproto.proto';

let packageDefinition;
try {
  packageDefinition = protoLoader.loadSync(PROTO_PATH, {
    keepCase: true,
    longs: String,
    enums: String,
    defaults: true,
    oneofs: true
  });
} catch (error) {
  console.error('Error loading proto file:', error);
}

const qProto = grpc.loadPackageDefinition(packageDefinition).myproto;
const client = new qProto.QEngine('localhost:6767', grpc.credentials.createInsecure())

// 封装gRPC调用为Promise
const queryWithPromise = (reqData: any): Promise<any> => {
  return new Promise((resolve, reject) => {
    client.Query(reqData, (err: Error, grpcResponse: any) => {
      if (err) {
        reject(err);
      } else {
        resolve(grpcResponse);
      }
    });
  });
};

export async function POST(req: NextRequest) {
  try {
    const body = await req.json();
    // 正确实例化gRPC请求对象
    const reqq = new qProto.QueryRequest();
    reqq.query_string = body.queryString;
    reqq.debug = body.debug;

    // 等待gRPC调用完成
    const grpcResponse = await queryWithPromise(reqq);
    return NextResponse.json({ data: grpcResponse }, { status: 200 });
  } catch (error) {
    console.error('Error:', error);
    return NextResponse.json({ error: 'Internal Server Error' }, { status: 500 });
  }
}

额外优化

  • 用const/let替换var,符合现代JS/TS规范。
  • 调整proto加载变量声明方式,避免变量提升问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.10 01:36:02