如何为带自定义请求头的异步POST请求应用Polly重试策略?
解决方案:每次重试生成新
HttpRequestMessage 你遇到的核心问题是预创建的HttpRequestMessage只能被发送一次,Polly重试时重复使用同一个实例就会抛出“请求已发送,无法复用”的异常。要同时满足重试和动态修改请求头的需求,最直接的解决方式是让Polly每次重试时都创建新的请求实例。
直接修改执行委托
把请求的创建逻辑放到ExecuteAsync的委托中,这样每次重试都会执行这段代码,生成全新的HttpRequestMessage:
using HttpResponseMessage response = await RetryPolicy.ExecuteAsync(() => { // 每次重试都会重新创建请求,动态设置请求头 HttpRequestMessage request = new(HttpMethod.Put, new Uri(url)); request.Content = new StringContent(GetJson(code), Encoding.UTF8, "text/json"); request.Headers.Add("tenant", GetId(code)); return Client.SendAsync(request); });
封装请求构建逻辑(优化代码整洁度)
如果多个地方需要类似逻辑,可以把请求创建抽成单独的方法,避免重复代码:
// 封装请求构建逻辑 private HttpRequestMessage CreateTenantPutRequest(string url, string code) { var request = new HttpRequestMessage(HttpMethod.Put, new Uri(url)); request.Content = new StringContent(GetJson(code), Encoding.UTF8, "text/json"); request.Headers.Add("tenant", GetId(code)); return request; } // 使用Polly重试时调用该方法 using HttpResponseMessage response = await RetryPolicy.ExecuteAsync(() => Client.SendAsync(CreateTenantPutRequest(url, code)) );
为什么这个方案可行?
- 避免了请求实例复用:每次重试都会生成全新的
HttpRequestMessage,不存在“已发送”的状态问题。 - 满足动态请求头需求:
GetId(code)每次都会重新执行,确保请求头是最新的(如果GetId的返回值可能变化的话)。
对之前尝试方法的补充说明
- 特定方法加请求头:确实没有直接的重载,但可以通过自定义
DelegatingHandler实现全局请求头注入,但如果是每次调用都需要动态变化的头,还是上述方法更直接。 - 修改客户端默认请求头:
HttpClient的默认头是线程不安全的,异步场景下容易出现竞态条件,不推荐用于动态变化的请求头。 - 每个租户一个客户端:会导致大量
HttpClient实例,违背了HttpClient应复用的最佳实践,浪费资源。 - 在重试处理程序中创建请求:不需要这么做,Polly的
ExecuteAsync委托本身就是每次重试都会执行的逻辑,把请求创建放在这里更符合设计逻辑。
内容的提问来源于stack exchange,提问作者Konrad Viltersten
相关产品推荐
相关产品推荐

