健康检查需手动添加具体检测逻辑,否则默认为空壳;数据库检查需显式配置连接和失败状态,自定义响应需安全序列化异常信息并注意中间件顺序。

健康检查不是加个中间件就完事——它默认不连数据库、不报错因、不显耗时,直接上生产等于裸奔。
为什么 AddHealthChecks() 注册后访问 /health 总是 Healthy?
因为默认注册的检查项全是“空壳”:没指定具体检测逻辑,AddHealthChecks() 只是搭了个架子。你得手动添加检查项,比如数据库、内存、磁盘等。
- EF Core 连接检查必须显式调用
AddSqlServer("connstr")或传入configureOptions启用includeEntityFramework,否则只是检查 DbContext 类型是否注册成功,根本不发连接请求 -
AddResourceUtilizationHealthCheck()需要引用Microsoft.Extensions.Diagnostics.HealthChecks.ResourceUtilization包,否则编译不通过 - 自定义检查类必须实现
IHealthCheck接口,且CheckHealthAsync方法里含异步 IO(如await conn.OpenAsync())时,绝不能用.Result或.Wait(),否则在同步上下文(如 IIS)中大概率死锁
如何让 /health 返回每个检查项的耗时和失败原因?
默认响应只含 status 和 results[].status,调试时根本看不出哪一步卡住了、为什么失败。必须替换默认 ResponseWriter。
- 开发环境用
Environment.IsDevelopment()判断,启用详细输出 - 自定义
ResponseWriter时,别直接序列化整个HealthReport——它包含Exception对象,JSON 序列化会抛异常;应提取Exception?.ToString()或Exception?.Message后再写入 - 示例片段:
app.MapHealthChecks("/health", new HealthCheckOptions<br>{<br> ResponseWriter = async (ctx, report) =><br> {<br> ctx.Response.ContentType = "application/json";<br> var json = JsonSerializer.Serialize(new<br> {<br> status = report.Status,<br> totalDuration = report.TotalDuration,<br> entries = report.Entries.ToDictionary(<br> kv => kv.Key,<br> kv => new { kv.Value.Status, kv.Value.Duration, kv.Value.Exception?.Message }<br> )<br> });<br> await ctx.Response.WriteAsync(json);<br> }<br>});
数据库健康检查为什么一直显示 Degraded 而不是 Unhealthy?
这是 EF Core 健康检查的默认行为:只要连接字符串能解析、DbContext 类型存在,就认为“可恢复”,状态设为 Degraded;只有明确抛出异常(如连接超时、认证失败)才变成 Unhealthy。
- 若想让连接失败立刻变
Unhealthy,需在AddSqlServer后追加failureStatus: HealthStatus.Unhealthy参数 - 并发执行多个检查时,一个 DB 检查失败不会中断其余检查(如内存、磁盘),但最终聚合状态取最差值;所以单个 DB 不可用,整体仍是
Unhealthy - 注意中间件顺序:
UseRouting()必须在MapHealthChecks()前,否则 404;而UseEndpoints()必须在其后,否则中间件链不生效
真正难的不是写几个 AddXxxHealthCheck(),而是理解每个检查项背后的执行时机、资源开销和失败传播逻辑——比如一个未配置超时的 Redis 检查,在网络抖动时可能拖慢整个健康端点响应,进而被 K8s 的 liveness probe 杀掉 Pod。










