Python调用gRPC .NET服务遇HTTP/2解析失败,单端口兼容JSON转码咨询
我们正在试验gRPC与JSON转码技术,以支持Delphi客户端调用服务,技术栈包含Python 3.10与.NET服务。使用.NET 7搭配Microsoft.AspNetCore.Grpc.JsonTranscoding包实现JSON转码,为测试定义了三个对应不同HTTP协议版本的端口:
webBuilder.UseKestrel(kestrelOptions => { kestrelOptions.ListenAnyIP(5000, listenOptions => { listenOptions.Protocols = Microsoft.AspNetCore.Server.Kestrel.Core.HttpProtocols.Http1; }); kestrelOptions.ListenAnyIP(5001, listenOptions => { listenOptions.Protocols = Microsoft.AspNetCore.Server.Kestrel.Core.HttpProtocols.Http2; }); kestrelOptions.ListenAnyIP(5002, listenOptions => { listenOptions.Protocols = Microsoft.AspNetCore.Server.Kestrel.Core.HttpProtocols.Http1AndHttp2; }); });
各端口测试情况:
- 5000端口:gRPC无法工作,但可通过JSON转码调用服务
- 5001端口:Python与.NET7客户端均可正常使用gRPC,但JSON转码无法工作
- 5002端口:仅.NET7客户端可使用gRPC,JSON转码正常;Python客户端触发如下错误:
grpc._channel._InactiveRpcError: <_InactiveRpcError of RPC that terminated with: status = StatusCode.UNAVAILABLE details = "failed to connect to all addresses; last error: UNAVAILABLE: ipv4:127.0.0.1:5000: Failed parsing HTTP/2" debug_error_string = "UNKNOWN:failed to connect to all addresses; last error: UNAVAILABLE: ipv4:127.0.0.1:5000: Failed parsing HTTP/2 {created_time:"2022-11-08T07:07:49.2047503+00:00", grpc_status:14}" >
Python客户端不支持协议协商,请问是否有办法在单端口同时启用JSON转码与两种协议?
使用版本:
-.NET 7.0.100-rc.2.22477.23
-Microsoft.AspNetCore.Grpc.JsonTranscoding 7.0.0-rc.2.22476.2
-Python 3.10.1
-grpcio 1.50.0
要在单端口同时支持JSON转码(依赖HTTP/1.1)和gRPC(依赖HTTP/2),并兼容Python客户端,可通过以下两种方案实现:
方案一:配置TLS启用ALPN协议协商
这是gRPC官方推荐的跨客户端兼容方案,通过TLS的ALPN(应用层协议协商)机制,Kestrel可自动区分HTTP/1.1和HTTP/2请求。修改Kestrel配置如下:
webBuilder.UseKestrel(kestrelOptions => { kestrelOptions.ListenAnyIP(5003, listenOptions => { listenOptions.Protocols = Microsoft.AspNetCore.Server.Kestrel.Core.HttpProtocols.Http1AndHttp2; // 配置证书,开发环境可使用dotnet dev-certs生成的证书 listenOptions.UseHttps("dev-cert.pfx", "password"); }); });
配置TLS后,Python的grpcio客户端会自动通过ALPN协商使用HTTP/2协议,解决解析错误问题,同时JSON转码的HTTP/1.1请求也能正常处理。
方案二:Python客户端强制使用明文HTTP/2(无TLS场景)
如果暂时无法配置TLS,可在Python客户端连接时强制指定h2c(明文HTTP/2)协议,绕过协议协商步骤:
import grpc # 创建通道时强制使用明文HTTP/2 channel = grpc.insecure_channel( "127.0.0.1:5002", options=[ ("grpc.http_protocol", "h2c"), ("grpc.default_authority", "localhost") ] )
此配置下,Python客户端会直接发送HTTP/2请求,与配置为Http1AndHttp2的Kestrel端口兼容,同时JSON转码功能不受影响。
验证效果
无论采用哪种方案,配置完成后单端口均可同时支持:
- Delphi客户端通过JSON转码(HTTP/1.1)调用服务
- .NET客户端通过gRPC(HTTP/2)调用服务
- Python客户端通过gRPC(HTTP/2)调用服务
内容的提问来源于stack exchange,提问作者KlemensE

