你在写 C# 后端,要给自己的 WebAPI 加一个调用外部服务的功能:可能是大模型接口,也可能是第三方业务接口。代码写出来跑得通,但一上生产就遇到超时、偶发失败、日志里看不出哪一步挂了。这篇按接入顺序把动作拆开:怎么建客户端、怎么发请求、超时和重试怎么设、日志记什么、接完怎么验证,给你一份能照着做的清单。
你在写 C# 后端,要给自己的 WebAPI 加一个调用外部服务的功能:可能是大模型接口,也可能是第三方业务接口。代码写出来跑得通,但一上生产就遇到超时、偶发失败、日志里看不出哪一步挂了。这篇按接入顺序把动作拆开,给你一份能照着做的清单。
下面四节分别对应接入过程中的四个阶段:建客户端、组装请求、配超时与重试、记日志并验证。每一节都给判断标准和可执行动作,遇到不适用的场景也会点出来,你可以按自己项目的实际情况取舍。
先把客户端建对:HttpClient 的注册与复用
最常见的坑是每次请求都 new 一个 HttpClient。短时间高频调用会把连接池打满,而且 DNS 变更不会及时生效。在 ASP.NET Core 里用 IHttpClientFactory 注册具名客户端,让框架帮你管理连接生命周期。如果项目还没上依赖注入,至少也要复用一个静态实例。
- 注册具名客户端在 Program.cs 或 Startup 里调用 AddHttpClient,给一个业务名,设置 BaseAddress。BaseAddress 从配置读,代码里只拼相对路径。
- 统一加鉴权头API Key 或 Bearer Token 在注册处通过 DefaultRequestHeaders 或自定义 DelegatingHandler 加上,业务方法里不再重复写鉴权逻辑。
- 验证复用生效接完后看连接数是否稳定,不再随请求量线性增长;换一次 BaseAddress 配置能生效即可确认不是硬编码。
请求怎么组装:方法、路径、Body 与序列化
请求组装看着简单,出问题多半在细节:方法选错、Content-Type 没设、字段名大小写对不上。建议把序列化配置集中一处,别在每个方法里各写各的。返回也先读字符串再反序列化,失败时原始报文能直接进日志。
| 关注点 | 推荐做法 | 常见错误 |
|---|---|---|
| HTTP 方法 | 查询用 GET,提交用 POST/PUT,Body 走 JSON | 用 GET 塞大 Body,网关直接丢弃 |
| 字段命名 | 用 JsonPropertyName 显式声明目标接口的命名约定 | 靠默认行为猜,线上字段对不上 |
| 请求头 | 显式设置 Content-Type 和 Accept | 缺失导致对方直接返回 4xx |
| 响应处理 | 先读字符串,再反序列化 | 直接反序列化,失败时拿不到原始报文 |
- 路径用相对路径拼接,BaseAddress 负责环境差异,换服务商只改配置
- 请求体序列化统一配置,别混用多种序列化库
- 返回先读字符串,日志里保留原始报文,排错时省一次复现
- 错误码分两类处理:4xx 看参数和鉴权,5xx 看对方服务状态
超时、重试与失败降级怎么配
超时不要只设一个笼统值。连接超时、单次请求超时、整体业务超时是三档不同的东西,混在一起会导致排查困难。具体秒数按你的服务实测基线来定,先到 /tools/speed-test 量一遍延迟分布,再决定阈值,这个数字不要照搬别人的。
重试只对幂等请求和瞬时错误做:连接失败、5xx、429 可以退避重试,写操作不要盲目重试,否则可能产生重复数据。重试要加次数上限和指数退避。超时和限流是两件事,超时解决单次等太久,限流解决并发打太高,排查前先分清。
- 连接超时
- 建立 TCP 连接阶段的等待上限,网络不通时最先触发
- 单次请求超时
- 一次 HTTP 调用从发出到收到响应的最长时间
- 整体业务超时
- 包含重试、降级在内的整段处理时间,用于兜底保护
- 降级
- 主接口失败时返回缓存值、默认值或明确错误码,避免整条链路挂掉
日志记什么,接完怎么验证通不通
日志的核心是让你在不复现的情况下判断挂在哪一步。每次调用至少记:目标地址、HTTP 状态码、耗时、请求 ID、错误摘要。不要把完整 Key 和敏感 Body 打进去,日志泄露是真实存在的风险。
接完先跑冒烟用例,三种场景都要覆盖:一条正常请求、一条故意用错鉴权的请求、一条触发超时的请求。三条都符合预期才算接完。线上再挂一个按小时统计失败率的监控,单次成功不代表稳定。
- 记目标地址和耗时,判断是慢还是不通
- 记 HTTP 状态码,区分鉴权和参数问题
- 记请求 ID(对方支持时),方便让对方协助排查
- 记录错误摘要而非完整报文,避免敏感信息落盘
- 线上按小时统计失败率,观察趋势而不是单点
验证顺序建议从后往前排查:先看日志有没有请求记录,再看响应状态码,最后看业务字段映射。这样能快速定位是网络层、协议层还是业务层的问题。
下一步如果你要接的是大模型类接口,先把各家接入方式和计费口径摸清楚再动手,站内资料库收录了调用约定和价格资料,可以去 /sites 核对当时的数字。→常见问题
HttpClient 到底该 new 还是该注入?
在 ASP.NET Core 的 WebAPI 里优先用 IHttpClientFactory 注入,它帮你管理连接池和 DNS 刷新。只有短生命周期的一次性脚本才适合直接 new。混着用常见后果是连接耗尽或者改了 DNS 不生效。
调用一直超时,从哪里开始查?
按顺序排:先确认地址和端口能不能通,再看是不是设了过短的超时,然后看对方是否限流返回 429,最后看 Body 是不是太大。用一次最简请求逐步加条件,比在完整代码里猜快得多。
重试几次比较合适?
没有统一数字,原则是只对幂等请求重试,次数控制在两三次以内,间隔用指数退避。写操作重试前先确认接口支持幂等键,否则可能产生重复数据,这种情况宁可不重试只报错。