如何创建将在超时后重新发送 HTTP 请求的可观察序列
本文关键字:请求 HTTP 新发送 观察 何创建 创建 超时 | 更新日期: 2023-09-27 18:33:46
我是Rx的新手,我正在尝试创建一个可观察序列,该序列将允许我执行以下操作:
- 使用 向 URI 发送 HTTP POST 请求System.Net.Http.HttpClient.SendAsync(request, cancelToken(
- 等待可配置的时间段返回响应或请求超时。
- 如果请求超时,则重复请求。
- 继续重复请求,直到收到响应(不必为 200 OK(或达到最大重试次数。
- 如果达到最大重试次数,那么我必须知道它,以便我可以记录错误。
我一直在玩:
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, "Some URI");
...
CancellationTokenSource tokenSource = new CancellationTokenSource();
CancellationToken token = tokenSource.Token;
...
try
{
var res = Observable.FromAsync(() => _client.SendAsync(request, token))
.Timeout(TimeSpan.FromSeconds(5));
try
{
HttpResponseMessage response = res.Wait();
// Process response
...
}
catch (TaskCancelledException)
{
....
}
}
catch (TimeoutException)
{
....
}
但我不确定在发生超时后再次启动请求的最佳方法,以及我应该如何检查我是否已达到最大重试次数。
此外,我不确定是否应该在可观察序列上放置超时策略,或者是否应该在 HttpClient 对象本身上设置 Timeout 属性。
[于2014年12月11日编辑]
根据下面的评论,我更新了@TheZenCoder的代码,以便它使用 await
var attempts = 0;
HttpResponseMessage response = null;
try
{
response = await Observable
.FromAsync((ct) =>
{
attempts++;
return SendRequest(token, ct);
})
.Retry(5)
.LastAsync();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
到目前为止,我只做了有限的测试,但它似乎工作正常。
要发送请求、设置请求超时并使用取消令牌,您可以将其包装到如下方法中:
private static Task<HttpResponseMessage> SendRequest(CancellationToken token)
{
var client = new HttpClient { Timeout = TimeSpan.FromSeconds(5) };
var request = new HttpRequestMessage(HttpMethod.Get, new Uri("http://www.google.ba"));
return client.SendAsync(request, token);
}
我认为在 HTTP 客户端上设置超时是一个更干净的选项,而不是使用可观察超时。
然后,您可以使用 IObservable Retry
方法多次重试此操作。如果您不害怕开源,RXX扩展中还有一些更灵活的重试方法,正如@Dave Sexton在评论中指出的那样。
var attempts = 0;
try
{
var response = Observable
.FromAsync(() =>
{
attempts++;
return SendRequest(token);
})
.Retry(5)
.Wait();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
如果 HTTP 超时或 SendRequest
方法中发生其他错误,则重试将继续。最后一次重试后将引发异常,其中包含有关错误的信息。重试次数设置为尝试次数变量。
请记住,使用 Wait
方法可以有效地阻止调用线程的执行,直到结果可用,这是您在使用异步代码时想要做的事情。也许您有一些特定的场景,这就是为什么我在我的示例中将其留在那里的原因。