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

.NET Framework 4.7.2的Grpc.Net.Client连接.NET6 gRPC服务失败

.NET Framework 4.7.2 gRPC客户端连接.NET6 HTTP/2服务端失败解决方案

问题复现

基于.NET Framework 4.7.2的Grpc.Net.Client客户端连接.NET6 gRPC服务端(HTTP/2-only)时失败:

  • 服务端报错:HTTP/2 over TLS was not negotiated on an HTTP/2-only endpoint.
  • 客户端报错:WinHttpException: Error 12030 calling WinHttpWriteData, 'The connection with the server was terminated abnormally'

核心原因

  1. HTTP/2协商不完整:.NET Framework的WinHttpHandler仅设置request.Version = 2.0不足以触发HTTP/2 ALPN协商,且缺少gRPC必需的TE: trailers请求头。
  2. 证书信任问题:若服务端使用自签名HTTPS证书,.NET Framework默认不信任该证书,会导致SSL握手失败,直接中断连接。

解决方案

1. 修复自定义HttpHandler,强制HTTP/2协商

修改Http2CustomHandler,补充HTTP/2配置和gRPC必需头:

public class Http2CustomHandler : WinHttpHandler
{
    protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
    {
        request.Version = new Version("2.0");
        // 添加gRPC要求的TE头,用于接收trailers
        request.Headers.Add("TE", "trailers");
        return base.SendAsync(request, cancellationToken);
    }

    protected override void InitializeHandle(SafeWinHttpHandle handle)
    {
        base.InitializeHandle(handle);
        // 通过WinHttp原生选项强制启用HTTP/2(WINHTTP_OPTION_ENABLE_HTTP2 = 12)
        int enableHttp2 = 1;
        WinHttpSetOption(handle, 12, ref enableHttp2, sizeof(int));
    }

    [DllImport("winhttp.dll", CharSet = CharSet.Unicode, SetLastError = true)]
    private static extern bool WinHttpSetOption(SafeWinHttpHandle hInternet, int dwOption, ref int lpBuffer, int dwBufferLength);
}

2. 处理自签名证书信任(开发环境)

如果服务端用的是自签名证书,需要让客户端信任它:

  • 方法一(推荐):将服务端证书导出,安装到客户端机器的受信任的根证书颁发机构存储区。
  • 方法二(仅开发用):代码中跳过证书验证(生产环境绝对禁止):
// 替换原Credentials配置
Credentials = new Grpc.Core.SslCredentials(new Grpc.Core.SslCertificateCredentials(
    (chain, errors) => true // 强制信任所有证书,仅限开发调试
))

3. 环境检查

确保客户端运行在**Windows 10 1607+或Windows Server 2016+**系统上,这些版本原生支持HTTP/2的ALPN协商,是.NET Framework使用HTTP/2的前提。

最终客户端代码

static void Main(string[] args)
{
    using (var channel = GrpcChannel.ForAddress("https://localhost:7193", new GrpcChannelOptions
    {
        HttpHandler = new Http2CustomHandler(),
        // 开发环境临时证书信任配置,生产环境替换为合法证书逻辑
        Credentials = new Grpc.Core.SslCredentials(new Grpc.Core.SslCertificateCredentials((chain, errors) => true))
    }))
    {
        var client = new Greeter.GreeterClient(channel);
        var reply = client.SayHelloAsync(new HelloRequest { Name = "GreeterClient" }).GetAwaiter().GetResult();
        Console.WriteLine("Greeting: " + reply.Message);
        Console.WriteLine("Press any key to exit...");
        Console.ReadKey();
    }    
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.12 05:14:51