HttpRequestMessage发送请求后被释放及API重试函数技术咨询
Hey there, let's break down how to fix your HttpRequestMessage disposal issue and walk through common pitfalls to check in your retry function.
The core issue here is that HttpClient.SendAsync automatically disposes the HttpRequestMessage after the request completes (unless you use HttpCompletionOption.ResponseHeadersRead and manually manage disposal). If you reuse the same HttpRequestMessage across retries, it'll be marked as disposed after the first attempt, causing errors on subsequent tries.
Here's how to fix it:
- Move the
HttpRequestMessagecreation inside yourwhileloop—generate a brand new request instance for every retry. - If your request uses
HttpContent, you also need to create a new instance each time (HttpContent gets disposed after being sent too, so reusing it will fail).
Here's a revised version of your function:
protected async Task<HttpResponseMessage> RetryIfExceptionAsync(string urlString, HttpMethod httpMethod, Func<HttpContent> httpContentFactory, byte exceptionRetries) { HttpResponseMessage httpResponse = null; byte retries = exceptionRetries; while (retries > 0) { // Create a fresh request for each retry using var httpRequest = new HttpRequestMessage() { RequestUri = new Uri(urlString), Method = httpMethod }; // Use a factory to get a new HttpContent instance every time if (httpContentFactory != null) { httpRequest.Content = httpContentFactory(); } try { httpResponse = await _httpClient.SendAsync(httpRequest); // Exit loop immediately if the request succeeds if (httpResponse.IsSuccessStatusCode) { break; } // Retry on non-success status codes (adjust based on your needs) retries--; // Add a delay to avoid overwhelming the API await Task.Delay(TimeSpan.FromSeconds(1)); } catch (Exception ex) { retries--; // Optional: Log the exception for debugging // _logger.LogError(ex, "Request failed, {RetriesLeft} retries remaining", retries); // Add a delay before retrying await Task.Delay(TimeSpan.FromSeconds(1)); } } return httpResponse; }
Using a Func<HttpContent> lets you pass a way to generate fresh content each time, instead of reusing a disposed instance.
Beyond the disposal problem, here are common pitfalls to check:
- Unmanaged HttpContent: If you were creating HttpContent outside the loop and reusing it, that's another disposal risk. Always create new content for each retry (like the factory pattern above).
- No retry delay: Firing off retries without waiting can trigger API rate limits or cause more failures. Use an exponential backoff (e.g., 1s, 2s, 4s delays) instead of fixed delays to be kinder to the target service.
- Retrying non-retryable errors: Not all failures should be retried. For example, 400 Bad Request (invalid parameters) or 401 Unauthorized (permission issues) won't fix themselves with retries. Add checks to only retry network errors, timeouts, or 5xx server errors.
- Unsafe HttpResponseMessage handling: If all retries fail, make sure you're not returning a null or disposed response. Callers should wrap the response in a
usingblock to ensure proper disposal:using var response = await RetryIfExceptionAsync(...); // Process the response - Incorrect retry counting: Double-check that your retry counter only decrements on failures, not on successful requests. Add logs to verify you're using the number of retries you expect (e.g., 3 retries mean 4 total attempts: 1 initial + 3 retries).
- Poor HttpClient management: If you're creating a new HttpClient for every request, you'll run into socket exhaustion issues. Use
IHttpClientFactory(recommended) or a singleton HttpClient instance instead.
内容的提问来源于stack exchange,提问作者Janilson

