You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Polly RetryAsync调用HttpClient.SendAsync时报请求已发送错误如何解决

异常产生原因
  • HttpRequestMessage 在.NET中被设计为单次使用对象,首次发送后内部会标记为已发送状态,同时关联的请求内容流会被释放,无法复用进行二次发送
  • 现有代码在重试策略外部创建了HttpRequestMessage实例,重试时直接复用了已经被发送过的对象,因此触发该错误
  • 附加注意:你传入的StringContent也属于流类型,仅支持一次读取,直接复用同样会导致重试时请求内容为空的问题
修复方案

核心逻辑是把请求对象创建、请求内容生成的逻辑放到重试策略的执行委托内部,每次重试都生成全新的请求实例:

方案1:修改方法签名,传入内容生成委托(推荐)

该方案无额外性能损耗,且灵活性更高:

public static async Task<HttpResponseMessage> Post(string specificUrl, string token, Func<StringContent> inputDataFactory)
{
    var policy = Policy
        .Handle<Exception>()
        .OrResult<HttpResponseMessage>(res => !res.IsSuccessStatusCode)
        .RetryAsync(3);

    string fullUrl = baseUrl + specificUrl;
    HttpResponseMessage res = await policy.ExecuteAsync(async () => 
    {
        using (var requestMessage = new HttpRequestMessage(HttpMethod.Post, fullUrl))
        {
            requestMessage.Content = inputDataFactory();
            requestMessage.Headers.Add("access_token", token);
            return await client.SendAsync(requestMessage).ConfigureAwait(false);
        }
    }).ConfigureAwait(false);
    return res;
}

调用示例:

// 原来的调用写法:Post("user/", token, new StringContent(json, Encoding.UTF8, "application/json"))
// 修改为传入生成Content的委托即可
await Post("user/", token, () => new StringContent(json, Encoding.UTF8, "application/json"));

方案2:兼容原有调用签名,提前缓存请求内容

如果不想修改现有调用逻辑,可以提前把请求内容缓存为字符串,每次重试重新生成StringContent:

public static async Task<HttpResponseMessage> Post(string specificUrl, string token, StringContent inputData)
{
    // 提前缓存请求内容,避免流被消费后无法读取
    string contentStr = await inputData.ReadAsStringAsync();
    var contentType = inputData.Headers.ContentType;
    
    var policy = Policy
        .Handle<Exception>()
        .OrResult<HttpResponseMessage>(res => !res.IsSuccessStatusCode)
        .RetryAsync(3);

    string fullUrl = baseUrl + specificUrl;
    HttpResponseMessage res = await policy.ExecuteAsync(async () => 
    {
        using (var requestMessage = new HttpRequestMessage(HttpMethod.Post, fullUrl))
        {
            requestMessage.Content = new StringContent(contentStr, contentType.CharSet, contentType.MediaType);
            requestMessage.Headers.Add("access_token", token);
            return await client.SendAsync(requestMessage).ConfigureAwait(false);
        }
    }).ConfigureAwait(false);
    return res;
}

内容的提问来源于stack exchange,提问作者Show More

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.05 23:36:01