名称: dotnet-service-communication 描述: “选择服务间协议。REST vs gRPC vs SignalR vs SSE 决策矩阵,权衡。” 用户可调用: false
dotnet-service-communication
高级路由技能,用于选择正确的服务通信协议。提供决策矩阵,将需求(延迟、方向、客户端类型、负载格式、浏览器支持)映射到五种主要的.NET通信协议:gRPC、SignalR、SSE、JSON-RPC 2.0 和 REST。路由到专门技能以获取实施深度。
范围
- gRPC、SignalR、SSE、JSON-RPC、REST 的决策矩阵
- 需求映射(延迟、方向、客户端类型、格式)
- 路由到专门实施技能
超出范围
- HTTP 客户端工厂和弹性管道 – 参见 [技能:dotnet-http-client] 和 [技能:dotnet-resilience]
- 原生 AOT 架构和修剪 – 参见 [技能:dotnet-native-aot] 和 [技能:dotnet-trimming]
交叉引用: [技能:dotnet-grpc] 用于 gRPC 实施, [技能:dotnet-realtime-communication] 用于 SignalR/SSE/JSON-RPC 详情, [技能:dotnet-http-client] 用于 REST/HTTP 客户端模式。参见 [技能:dotnet-integration-testing] 用于测试服务通信模式。
决策矩阵
使用此矩阵根据您的需求选择正确的协议:
| 需求 | gRPC | SignalR | SSE | JSON-RPC 2.0 | REST |
|---|---|---|---|---|---|
| 方向 | 所有四种模式 | 全双工 | 服务器到客户端 | 请求-响应 | 请求-响应 |
| 传输格式 | Protobuf(二进制) | JSON 或 MessagePack | 文本(JSON 行) | JSON | JSON/XML |
| 浏览器支持 | gRPC-Web(需要代理) | 是(JS 客户端) | 是(原生 EventSource) | 通过 WebSocket | 是(fetch/XHR) |
| 契约 | .proto 模式 |
Hub 接口 | 约定 | JSON-RPC 规范 | OpenAPI/Swagger |
| 延迟 | 最低 | 低 | 低 | 中等 | 中等 |
| 吞吐量 | 最高 | 高 | 中等 | 中等 | 中等 |
| 流式传输 | 所有 4 种模式 | 服务器 + 客户端流式 | 仅服务器推送 | 否 | 否(分块传输) |
| 连接 | HTTP/2 持久 | WebSocket(有回退) | HTTP/1.1+ 持久 | 传输依赖 | 按请求 |
| 服务到服务 | 优秀 | 好 | 有限 | 小众 | 好 |
| AOT 友好 | 是(Protobuf) | 是 | 是 | 是 | 是(使用 STJ 源生成) |
决策流程图
这是服务到服务(无浏览器)吗?
├── 是 → 您需要流式传输吗?
│ ├── 是 → gRPC 流式传输 [技能:dotnet-grpc]
│ └── 否 → 是请求-响应吗?
│ ├── 高吞吐量 / 二进制 → gRPC(单播) [技能:dotnet-grpc]
│ └── 标准 CRUD / 公共 API → REST [技能:dotnet-http-client]
└── 否(浏览器客户端) → 您需要实时吗?
├── 是 → 您需要双向吗?
│ ├── 是 → SignalR [技能:dotnet-realtime-communication]
│ └── 否(仅服务器推送) → SSE [技能:dotnet-realtime-communication]
└── 否 → REST [技能:dotnet-http-client]
特殊情况:
- LSP / 工具协议 → JSON-RPC 2.0 [技能:dotnet-realtime-communication]
- 混合(浏览器 + 服务到服务) → 浏览器用 REST,内部用 gRPC
协议概况
gRPC
最适合: 服务到服务通信、高吞吐量流式传输、强类型契约。
- 使用
.proto文件进行模式优先开发 - 所有四种流式模式:单播、服务器流式、客户端流式、双向
- 二进制序列化(Protobuf)以获得最小负载和最快吞吐量
- 内置客户端和服务器存根代码生成
- 原生负载均衡和健康检查协议支持
何时不使用: 直接浏览器通信(需要 gRPC-Web 代理)、由外部客户端使用的简单 CRUD API、需要人类可读负载的场景。
参见 [技能:dotnet-grpc] 获取完整实施详情。
SignalR
最适合: 面向浏览器的实时应用程序、交互式仪表板、聊天、协作功能。
- 自动传输协商(WebSocket → SSE → 长轮询)
- 内置组管理和用户定位
- Hub 抽象与强类型接口
- 通过 Redis 背板或 Azure SignalR 服务扩展
- 支持 JSON 和 MessagePack 序列化
何时不使用: 仅服务器到客户端推送(使用 SSE 代替)、服务到服务(使用 gRPC 代替)、无法包含 SignalR 客户端库的场景。
参见 [技能:dotnet-realtime-communication] 获取 SignalR 模式和 Hub 实施。
服务器发送事件(SSE)
最适合: 简单服务器到客户端推送通知、实时源、状态更新。
- 在 .NET 10 中通过
TypedResults.ServerSentEvents内置到 ASP.NET Core - 浏览器原生
EventSourceAPI – 无需客户端库 - 使用
Last-Event-ID自动重新连接 - 通过阻塞 WebSocket 升级的 HTTP/1.1 代理工作
- 最轻量级的实时选项
何时不使用: 双向通信(使用 SignalR)、高吞吐量二进制流式传输(使用 gRPC)、需要客户端到服务器消息。
参见 [技能:dotnet-realtime-communication] 获取 SSE 实施详情。
JSON-RPC 2.0
最适合: 工具协议(语言服务器协议)、通过简单传输的结构化 RPC。
- 传输无关(HTTP、WebSocket、stdio、命名管道)
- 定义良好的请求/响应/通知语义
- 由 Visual Studio、VS Code 和 .NET 工具通过 StreamJsonRpc 使用
- 当不需要模式管理时,作为 gRPC 的轻量级替代品
何时不使用: 实时流式传输(使用 SignalR 或 gRPC)、高吞吐量服务到服务(使用 gRPC)、标准 Web API(使用 REST)。
参见 [技能:dotnet-realtime-communication] 获取 JSON-RPC 2.0 模式。
REST(HTTP API)
最适合: 公共 API、标准 CRUD 操作、广泛的客户端兼容性。
- 通用客户端支持(任何 HTTP 客户端)
- 人类可读负载(JSON)
- 丰富的生态系统(OpenAPI、Swagger UI、API 版本控制)
- 无状态请求-响应模型
- ASP.NET Core Minimal API 或 MVC 控制器
何时不使用: 实时推送(使用 SSE 或 SignalR)、高吞吐量服务到服务(使用 gRPC)、双向流式传输(使用 SignalR 或 gRPC)。
参见 [技能:dotnet-http-client] 获取 HTTP 客户端模式、弹性和 IHttpClientFactory。
常见架构模式
使用混合协议的 API 网关
浏览器 ─── REST/SignalR ──→ API 网关 ──→ gRPC ──→ 内部服务
──→ gRPC ──→ 订单服务
──→ gRPC ──→ 库存服务
公共面向的 API 使用 REST,实时浏览器功能使用 SignalR。内部服务到服务通信使用 gRPC 以提高性能。API 网关在协议之间转换。
事件驱动与 SSE
内部服务 ──→ 消息代理 ──→ SSE 端点 ──→ 浏览器仪表板
──→ gRPC 流 ──→ 监控服务
内部事件流经消息代理。浏览器仪表板通过 SSE 消费。其他服务通过 gRPC 流式传输消费以获得更高吞吐量。
双协议服务
单个 ASP.NET Core 主机可以同时服务 gRPC 和 REST:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddGrpc();
builder.Services.AddControllers();
var app = builder.Build();
// gRPC 用于内部服务到服务
app.MapGrpcService<OrderGrpcService>();
// REST 用于外部客户端
app.MapControllers();
// SSE 用于实时浏览器更新
app.MapGet("/events/orders", (OrderEventService svc, CancellationToken ct) =>
TypedResults.ServerSentEvents(svc.GetEventsAsync(ct)));
关键原则
- 服务到服务使用 gRPC – 提供最佳吞吐量、强类型契约和所有流式模式
- 公共 API 使用 REST – 通用客户端支持、人类可读、广泛的工具生态系统
- 浏览器实时使用 SignalR – 自动传输协商和内置组管理
- 简单服务器推送使用 SSE – 当不需要双向通信时的轻量级选项
- 适当混合协议 – 单个 ASP.NET Core 主机可以同时服务 gRPC、REST、SignalR 和 SSE
- 基于客户端类型路由 – 浏览器客户端获取 REST/SignalR/SSE;内部服务获取 gRPC
参见 [技能:dotnet-native-aot] 获取 AOT 编译管道和 [技能:dotnet-aot-architecture] 获取 AOT 兼容通信模式。
代理注意事项
- 不要默认将 gRPC 用于面向浏览器的 API – 浏览器无法本地处理 HTTP/2 尾部。使用 gRPC-Web 和代理或选择 REST/SignalR/SSE。
- 不要将 SignalR 用于服务到服务 – gRPC 为后端通信提供更好的性能、代码生成和流式传输。
- 当 SSE 足够时不要添加 SignalR – 如果仅需要服务器到客户端推送,SSE 更简单,无需客户端库,并且浏览器有自动重新连接。
- 不要将 REST 用于高吞吐量内部通信 – JSON 文本序列化和按请求连接相比 gRPC 的二进制格式和持久 HTTP/2 连接增加开销。
- 不要忘记 AOT 考虑 – 使用 System.Text.Json 的 REST 端点需要源生成上下文用于 AOT。参见 [技能:dotnet-serialization] 获取详情。
- 不要将 gRPC 服务暴露给不受信任的客户端而不使用 gRPC-Web – 原始 gRPC 需要 HTTP/2,这在所有环境中并非普遍可用(例如,某些代理、旧浏览器)。