.NET6 Kestrel设仅HTTP/2时健康检查报TLS未协商HTTP/2错误
问题根因
这个报错和健康检查功能本身无关,是Kestrel配置错误导致所有请求都无法正常处理,核心问题有三个:
- 协议与端点类型不匹配:你给端点默认配置了仅
Http2协议,Kestrel的纯Http2模式默认要求必须通过TLS握手的ALPN扩展协商HTTP/2协议,但你绑定的是无TLS的明文HTTP地址,根本不存在TLS协商流程,自然会抛出协商失败错误。 - Kestrel配置结构写错:你把
Http端点节点写在了EndpointDefaults层级下,正确的端点配置应该放在Endpoints节点下,当前配置下你写的http://localhost:5020根本不会被Kestrel加载。 - 健康检查UI额外兼容问题:你给UI配置的探测地址是相对路径,UI内部发起请求时默认走HTTP/1.1协议,就算Kestrel端配置正确,也可能出现探测失败的问题。
解决方案
根据你是否需要TLS选对应方案即可。
方案1:内网场景使用明文HTTP/2(h2c)
如果服务仅在内网服务间调用、不需要TLS加密,按如下修改:
- 修正Kestrel配置结构,将协议改为同时支持HTTP/1.1和HTTP/2(明文h2c需要通过HTTP/1.1的Upgrade头协商,必须开启HTTP/1.1支持):
"Kestrel": { "EndpointDefaults": { "Protocols": "Http1AndHttp2" }, "Endpoints": { "Http": { "Url": "http://localhost:5020" } } }
- 修正健康检查UI配置,写全探测端点的绝对地址,同时配置UI内部客户端支持明文HTTP/2请求:
services.AddHealthChecksUI(setup => { setup.SetEvaluationTimeInSeconds(60); // 替换为你实际的服务监听地址 setup.AddHealthCheckEndpoint("Basic Health Check", "http://localhost:5020/healthz"); // 配置探测客户端使用HTTP/2协议 setup.ConfigureApiEndpointHttpMessageHandler = handler => { if (handler is HttpClientHandler clientHandler) { clientHandler.DefaultRequestVersion = HttpVersion.Version20; clientHandler.DefaultVersionPolicy = HttpVersionPolicy.RequestVersionOrHigher; } return handler; }; }).AddInMemoryStorage();
*注意:所有主流浏览器都不支持明文HTTP/2(h2c),该方案仅适合服务间内部调用场景,如果需要给浏览器端提供访问能力,请选方案2的TLS模式。
方案2:公网/浏览器访问场景使用HTTP/2 over TLS
如果服务需要对外提供访问、走标准TLS加密,按如下修改:
- 修正Kestrel配置,绑定HTTPS端点和证书,保留仅HTTP/2配置:
"Kestrel": { "EndpointDefaults": { "Protocols": "Http2" }, "Endpoints": { "Https": { "Url": "https://localhost:5021", // 开发环境可以去掉Certificate节点,直接使用.NET内置开发证书 "Certificate": { "Path": "你的服务端证书.pfx", "Password": "证书导出密码" } } } }
- 修正健康检查UI的探测地址为HTTPS绝对路径即可,不需要额外修改客户端协议配置:
services.AddHealthChecksUI(setup => { setup.SetEvaluationTimeInSeconds(60); setup.AddHealthCheckEndpoint("Basic Health Check", "https://localhost:5021/healthz"); }).AddInMemoryStorage();
额外建议
如果你的服务前面会挂Nginx、YARP等反向代理,不需要在Kestrel层强制HTTP/2,只需要在反向代理层做HTTP/2卸载,Kestrel和代理之间走HTTP/1.1通信即可,能避免h2c协商的各种兼容问题,稳定性更高。
验证方式
重启服务后先用命令行工具直接请求健康检查端点验证Kestrel配置是否生效:
# 明文场景用这个命令 curl --http2-prior-knowledge http://localhost:5020/healthz # TLS场景用这个命令 curl --http2 https://localhost:5021/healthz
如果返回200状态码和健康检查结果,说明Kestrel端配置正常,再访问/healthcheck-ui页面,查看健康状态显示正常即全部配置完成。
内容的提问来源于stack exchange,提问作者Matt
相关产品推荐
相关产品推荐

