NetCore+Web客户端实现gRPC实时推送

📅 2026/7/26 1:18:03
NetCore+Web客户端实现gRPC实时推送
NetCoreWeb客户端实现gRPC实时推送引言在现代Web应用中实时推送是一个常见需求比如股票行情、聊天消息、系统通知等。传统的HTTP轮询方式效率低下且延迟高而WebSocket虽然解决了部分问题但在微服务架构中gRPC凭借其高性能、强类型和双向流特性成为实时推送的理想选择。本文将带你从零开始使用.NET CoreNetCore作为服务端结合gRPC实现实时推送并在Web客户端JavaScript中接收推送数据。我们将通过两个完整的代码示例来演示整个过程。## 技术栈与环境准备-服务端: .NET 8 (NetCore)-客户端: 纯HTML JavaScript (使用gRPC-Web)-通信协议: gRPC Protobuf-工具: Visual Studio 2022, Node.js (用于测试)在开始之前确保已安装- .NET SDK 8.0± Node.js 18## 1. 创建gRPC服务端项目首先我们创建一个gRPC服务端项目用于定义服务和推送逻辑。### 1.1 定义Protobuf协议创建一个名为ChatService的gRPC服务支持双向流推送。protobuf// chat.protosyntax proto3;package chat;// 聊天服务定义service ChatService { // 双向流客户端发送消息服务端返回实时通知 rpc ChatStream (stream ChatMessage) returns (stream Notification);}// 客户端发送的消息结构message ChatMessage { string user 1; // 用户名 string content 2; // 消息内容 int64 timestamp 3; // 时间戳毫秒}// 服务端推送的通知结构message Notification { string type 1; // 通知类型new_message, system string payload 2; // 通知内容JSON格式 int64 timestamp 3; // 时间戳}### 1.2 实现服务端逻辑在.NET Core中实现ChatService并添加实时推送功能。csharp// Services/ChatService.csusing Grpc.Core;using ChatGrpc; // 自动生成的代码namespace GrpcServer.Services;public class ChatServiceImpl : ChatService.ChatServiceBase{ private static readonly ListIServerStreamWriterNotification _clients new(); private static readonly object _lock new(); // 处理双向流接收客户端消息并广播通知 public override async Task ChatStream( IAsyncStreamReaderChatMessage requestStream, IServerStreamWriterNotification responseStream, ServerCallContext context) { // 将当前客户端加入广播列表 lock (_lock) { _clients.Add(responseStream); } try { // 持续读取客户端发送的消息 await foreach (var message in requestStream.ReadAllAsync()) { // 构造通知对象 var notification new Notification { Type new_message, Payload ${{\user\:\{message.User}\,\content\:\{message.Content}\,\timestamp\:{DateTimeOffset.UtcNow.ToUnixTimeMilliseconds()}}}, Timestamp DateTimeOffset.UtcNow.ToUnixTimeMilliseconds() }; // 广播给所有客户端包括自己 lock (_lock) { foreach (var client in _clients) { // 异步发送不等待 _ client.WriteAsync(notification); } } Console.WriteLine($收到消息: {message.User} - {message.Content}); } } catch (Exception ex) { Console.WriteLine($客户端断开连接: {ex.Message}); } finally { // 移除断开的客户端 lock (_lock) { _clients.Remove(responseStream); } } }}### 1.3 配置服务端启动在Program.cs中配置gRPC服务并启用gRPC-Web支持用于浏览器客户端。csharp// Program.csusing GrpcServer.Services;var builder WebApplication.CreateBuilder(args);// 添加gRPC服务builder.Services.AddGrpc();// 添加gRPC-Web支持必须builder.Services.AddGrpcWeb(o o.GrpcWebEnabled true);var app builder.Build();// 启用gRPC-Web中间件app.UseGrpcWeb();// 映射gRPC服务app.MapGrpcServiceChatServiceImpl().EnableGrpcWeb();// 添加静态文件支持用于提供HTML客户端app.UseDefaultFiles();app.UseStaticFiles();app.Run();## 2. 创建Web客户端Web客户端使用JavaScript通过gRPC-Web协议与服务端通信。这里我们使用grpc/grpc-js和grpc/proto-loader库需要Node.js环境打包或直接在浏览器中使用CDN。### 2.1 安装依赖bash# 初始化项目npm init -y# 安装gRPC-Web客户端库npm install grpc/grpc-js grpc/proto-loader### 2.2 编写HTML客户端创建一个简单的HTML页面实现消息发送和实时接收。html!-- wwwroot/index.html --!DOCTYPE htmlhtml langzh-CNhead meta charsetUTF-8 titlegRPC实时推送演示/title style #messages { height: 400px; overflow-y: scroll; border: 1px solid #ddd; padding: 10px; } .message { margin-bottom: 10px; } .user { font-weight: bold; color: #007bff; } .time { color: #666; font-size: 0.8em; } /style/headbody h1gRPC实时聊天/h1 div idmessages/div div input typetext iduserInput placeholder用户名 valueUser / input typetext idmessageInput placeholder输入消息... / button onclicksendMessage()发送/button /div !-- 引入gRPC-Web库 -- script srchttps://unpkg.com/grpc/grpc-js1.10.0/build/grpc.js/script script srchttps://unpkg.com/grpc/proto-loader0.7.10/build/index.js/script script // 定义gRPC连接 const host http://localhost:5000; // 服务端地址 const protoFile chat.proto; // 需要服务端提供proto文件 // 加载proto定义 const packageDefinition grpc.loadSync(protoFile, { keepCase: true, longs: String, enums: String, defaults: true, oneofs: true }); const proto grpc.loadPackageDefinition(packageDefinition).chat; // 创建客户端 const client new proto.ChatService(host, grpc.credentials.createInsecure()); // 建立双向流连接 const call client.chatStream(); // 接收服务端推送的通知 call.on(data, function(notification) { const payload JSON.parse(notification.payload); const messagesDiv document.getElementById(messages); const msgElement document.createElement(div); msgElement.className message; msgElement.innerHTML span classuser${payload.user}/span span classtime${new Date(payload.timestamp).toLocaleTimeString()}/span div${payload.content}/div ; messagesDiv.appendChild(msgElement); messagesDiv.scrollTop messagesDiv.scrollHeight; }); // 处理错误和关闭事件 call.on(error, function(err) { console.error(gRPC错误:, err); }); call.on(end, function() { console.log(连接关闭); }); // 发送消息函数 function sendMessage() { const user document.getElementById(userInput).value || 匿名; const content document.getElementById(messageInput).value; if (!content) return; const message { user: user, content: content, timestamp: Date.now() }; // 通过gRPC流发送消息 call.write(message); document.getElementById(messageInput).value ; } // 按回车键发送 document.getElementById(messageInput).addEventListener(keypress, function(e) { if (e.key Enter) { sendMessage(); } }); /script/body/html## 3. 运行与测试### 3.1 启动服务端在服务端项目目录下执行bashcd GrpcServerdotnet run服务端将在http://localhost:5000启动。### 3.2 访问Web客户端在浏览器中打开http://localhost:5000你会看到聊天界面。打开两个浏览器窗口分别输入不同用户名发送消息后所有窗口都会实时收到推送。### 3.3 测试效果- 在窗口1输入用户A和消息HellogRPC!- 在窗口2输入用户B和消息收到- 两个窗口会立即显示对方发送的消息延迟通常在毫秒级。## 4. 关键点解析### 4.1 gRPC-Web的作用浏览器原生不支持HTTP/2和gRPC的二进制传输因此需要使用gRPC-Web协议进行适配。服务端通过EnableGrpcWeb()中间件将gRPC转换为gRPC-Web格式使得浏览器可以正常通信。### 4.2 双向流推送的优势-低延迟: 服务端可以立即推送数据无需客户端轮询。-节省带宽: 只在有数据时传输避免了HTTP长连接的头部开销。-强类型: 通过Protobuf定义数据结构减少解析错误。### 4.3 生产环境注意事项- 使用gRPC.Web库如Grpc.Net.Client.Web替代手动加载proto。- 添加认证和授权机制如JWT。- 使用连接池管理大量客户端连接。- 考虑使用Redis或Kafka实现服务间推送广播。## 总结本文通过一个完整的聊天示例演示了如何使用.NET CoreNetCore实现gRPC服务端并通过Web客户端JavaScript接收实时推送。我们涵盖了从Protobuf定义、服务端实现、客户端集成到实际运行测试的全过程。gRPC的实时推送能力不仅适用于聊天场景还可以扩展到物联网数据上报、金融行情推送、多人协作编辑等需要低延迟、高吞吐的领域。结合.NET Core的高性能和跨平台特性这一方案在微服务架构中具有极高的实用价值。希望这篇文章能帮助你快速上手gRPC实时推送技术并在实际项目中灵活运用。如果有任何问题欢迎在评论区交流讨论