如何在Next.js函数式组件中调用.NET 6 gRPC服务端?
解决Next.js(TypeScript)调用.NET 6 gRPC服务的方案
一、错误原因说明
你使用的grpc和@grpc/proto-loader是Node.js专属库,依赖Node.js的fs文件系统模块,但浏览器环境没有该模块,因此在Next.js客户端组件中运行会出现Can't resolve 'fs'的错误。浏览器无法直接调用原生gRPC服务,必须通过gRPC-Web协议做适配。
二、前置准备:配置.NET 6 gRPC服务支持gRPC-Web
首先需要让你的.NET gRPC服务兼容gRPC-Web协议:
- 在gRPC服务项目中安装NuGet包:
Grpc.AspNetCore.Web - 修改
Program.cs添加gRPC-Web支持:
var builder = WebApplication.CreateBuilder(args); // 注册gRPC服务 builder.Services.AddGrpc(); var app = builder.Build(); // 启用gRPC-Web中间件(需放在MapGrpcServices之前) app.UseGrpcWeb(); // 映射Greeter服务并允许gRPC-Web访问 app.MapGrpcService<GreeterService>().EnableGrpcWeb(); app.Run();
三、Next.js项目配置步骤
1. 安装依赖包
安装gRPC-Web客户端相关工具:
npm install @grpc/grpc-web @improbable-eng/grpc-web google-protobuf npm install -D protobuf-loader-typescript-plugin @types/google-protobuf
2. 编译.proto文件生成TypeScript代码
手动编写TS类型效率低,用工具将.proto文件编译成可直接使用的TS代码:
- 将你的
greet.proto文件放到Next.js项目的proto目录下(例如/proto/greet.proto) - 在项目根目录创建
proto-gen.js脚本:
const path = require('path'); const protobuf = require('protobufjs'); const { generateTsCode } = require('@improbable-eng/grpc-web/codegen'); // 加载并编译proto文件 protobuf.load(path.resolve(__dirname, './proto/greet.proto'), (err, root) => { if (err) throw err; const outputPath = path.resolve(__dirname, './src/generated/greet.ts'); // 生成TypeScript客户端代码 const tsCode = generateTsCode(root, 'greet.proto', { outputPath, }); // 写入文件 require('fs').writeFileSync(outputPath, tsCode); });
- 在
package.json中添加编译命令:
"scripts": { "proto:gen": "node proto-gen.js" }
- 运行命令生成代码:
npm run proto:gen
生成的代码会保存在src/generated/greet.ts,包含gRPC客户端和消息类型的完整定义。
3. 编写Next.js函数式组件实现点击调用
修改pages/index.tsx,使用生成的代码实现点击触发gRPC调用:
import type { NextPage } from "next"; import styles from "../styles/Home.module.css"; import { GreeterClient } from "../src/generated/greet"; import { HelloRequest } from "../src/generated/greet_pb"; const Home: NextPage = () => { // 初始化gRPC-Web客户端(替换为你的.NET服务地址) const client = new GreeterClient("http://localhost:5000", null, null); const grpcCall = () => { const request = new HelloRequest(); request.setName("Say Hello"); // 回调模式调用gRPC接口 client.sayHello(request, {}, (err, response) => { if (err) { console.error("调用失败:", err); return; } console.log("gRPC响应:", response?.getMessage()); alert(`收到响应: ${response?.getMessage()}`); }); // 也可以使用Promise模式: // client.sayHelloPromise(request, {}) // .then(response => alert(`收到响应: ${response.getMessage()}`)) // .catch(err => console.error("调用失败:", err)); }; return ( <div className={styles.container}> <div onClick={grpcCall} className={styles.title} style={{cursor: 'pointer'}}> Press to call gRPC HERE </div> </div> ); }; export default Home;
四、关键注意事项
- 端口与协议:gRPC-Web默认使用HTTP/HTTPS,确保.NET服务的HTTP端口(例如5000)正常开启,客户端地址需与服务地址完全匹配。
- 跨域处理:若Next.js与gRPC服务不在同一域名/端口,需在.NET服务中配置CORS:
在Program.cs中添加:builder.Services.AddCors(options => { options.AddPolicy("AllowAll", policy => { policy.AllowAnyOrigin() .AllowAnyMethod() .AllowAnyHeader() .WithExposedHeaders("Grpc-Status", "Grpc-Message", "Grpc-Encoding", "Grpc-Accept-Encoding"); }); }); // 在UseGrpcWeb之前启用CORS app.UseCors("AllowAll"); - 调用模式:gRPC-Web支持回调和Promise两种调用模式,可根据需求选择。
内容的提问来源于stack exchange,提问作者Raitis Lebedevs
相关产品推荐
相关产品推荐

