HttpRequestMessage
只能发送一次。尝试重新发送它会导致 InvalidOperationException
。
那么 Polly 如何能够规避这种行为,换句话说,当将 AddPolicyHandler
与重试策略一起使用时,幕后发生了什么?我知道它使用 DelegatingHandler
但它如何能够多次处理同一消息?
最佳答案
TL;DR:这与 Polly 无关。
让我们从一个示例开始,该示例在第二次尝试时失败并出现 InvalidOperationException
。
var request = new HttpRequestMessage(HttpMethod.Get, "https://httpstat.us/500");
var httpClient = new HttpClient(new HttpClientHandler());
for(int i = 0; i < 3; i++)
{
var result = await httpClient.SendAsync(request);
result.StatusCode.Dump();
}
如果我们将请求对象的创建移到 for 循环内,那么一切都会好起来的。但让我们将其保留在 for
之外。
让我们创建一个简单的委托(delegate)处理程序
public class RetryHandler : DelegatingHandler
{
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
HttpResponseMessage result = null;
for(int i = 0; i < 3; i++)
{
result = await base.SendAsync(request, cancellationToken);
"Retried".Dump();
}
return result;
}
}
让我们使用它
var handler = new RetryHandler();
handler.InnerHandler = new HttpClientHandler();
var httpClient = new HttpClient(handler);
var request = new HttpRequestMessage(HttpMethod.Get, "https://httpstat.us/500");
var result = await httpClient.SendAsync(request);
result.StatusCode.Dump();
此版本不会抛出任何 InvalidOperationException
。
那么,为什么后者有效而前者无效?
CheckRequestMessage
抛出 InvalidOperationException
HttpClient
private static void CheckRequestMessage(HttpRequestMessage request)
{
if (!request.MarkAsSent())
{
throw new InvalidOperationException(SR.net_http_client_request_already_sent);
}
}
此方法正在由 CheckRequestBeforeSend
调用。这是 SendAsync
的第一个命令。此公共(public) SendAsync
调用其 base's SendAsync
。这里的base
是一个HttpMessageInvoker
,其中deals with the HttpMessageHandler
.
长话短说:
- 如果您想在
HttpClient
之外重用HttpRequestMessage
,那么由于CheckRequestMessage
调用,第二次尝试将会失败 >
- 如果您想在
DelegatingHandler
(HttpMessageHandler
) 中重用HttpRequestMessage
,那么它不会失败,因为HttpMessageInvoker
does not care关于重用
关于c# - Polly 如何能够重新发送相同的 HTTP 请求?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/76058694/