HTTP 请求超时
问题和触发条件
原来的共享 HTTP 宿主没有请求处理期限。Reference 的数据库和消息接口已经接收 CancellationToken,但客户端保持连接且下游迟迟不返回时,服务端不会主动取消这些工作。单纯设置 HttpClient.Timeout 只约束调用方;服务端仍可能继续执行查询或写入。
ASP.NET Core 的请求超时中间件在期限到达时取消 HttpContext.RequestAborted。端点和下游调用必须继续传递这个 token 并响应取消。中间件不能强制结束忽略取消的同步或异步工作;如果响应已经开始,也不能把它改写成完整的 504 响应。因此这里的超时是服务端协作取消机制,不是对任意代码的强制中断。
本次方案
AddPlatformRequestTimeouts 和 UsePlatformRequestTimeouts 显式接入 ASP.NET Core 内置的请求超时组件。宿主可以直接在 RequestTimeoutOptions 中设置默认策略或命名策略,再用 WithRequestTimeout 关联端点或路由组。不配置策略时,注册中间件本身不会给请求设定期限。
Reference 的 Http:RequestTimeouts:Enabled 默认为 false。启用后,所有业务 API 端点共用 reference-api-timeout 策略,默认期限为 30 秒;可以通过 Http:RequestTimeouts:Seconds 设置正整数秒数。存活和就绪端点没有附加该策略。无效的布尔值或非正秒数会在服务组合阶段报错。策略超时且端点按约定响应取消时,未开始的响应返回 504。
Reference 的管线顺序是:转发头、路由、CORS、请求日志、请求超时、认证、授权、限流、端点。超时中间件需要位于路由后,才能看到端点策略;它放在认证、授权和限流前,因此这些处理时间也属于 API 期限。授权先拒绝 401、403,限流再按已验证身份分区。请求日志包住超时中间件,能够记录超时响应。
| 情况 | 行为 |
|---|---|
| API 在期限内完成 | 返回原有响应。 |
| API 超时,端点观察取消且响应尚未开始 | RequestAborted 被取消;中间件返回 504。 |
| 客户端先取消请求 | 客户端的调用取消;服务端观察 RequestAborted,不会把这次取消当作超时响应交给客户端。 |
| Reference 健康端点 | 不使用 API 命名超时策略。 |
| 宿主设置全局默认策略 | 未指定其他策略的端点也会超时;可用 DisableRequestTimeout 显式豁免。 |
新增代码使用框架内置组件、静态类型和显式读取配置,没有引入运行时反射或动态代码生成。这项工作补充行为边界,未进行性能优化,也没有前后吞吐数据。
验证与后续
TestServer 验证了慢端点取消 RequestAborted 并返回 504、正常请求成功、健康端点豁免、调用方先取消、Reference 的 API/健康端点策略元数据,以及配置错误在启动时被拒绝。这些测试验证中间件和端点接线;它们不证明真实数据库、代理或长连接在超时后的资源释放时间。
不同 API 的合理期限可能相差很大。当前 Reference 为控制配置范围只提供一个 API 策略;确有需要时,可以为特定端点指定另一命名策略。对写请求还要明确事务和幂等语义:取消信号到达时,外部依赖可能已经提交,客户端收到 504 不代表写入一定失败。这需要由写请求幂等功能单独处理。