如何创建将在超时后重新发送 HTTP 请求的可观察序列

本文关键字:请求 HTTP 新发送 观察 何创建 创建 超时 | 更新日期: 2023-09-27 18:33:46

我是Rx的新手,我正在尝试创建一个可观察序列,该序列将允许我执行以下操作:

  1. 使用 向 URI 发送 HTTP POST 请求System.Net.Http.HttpClient.SendAsync(request, cancelToken(
  2. 等待可配置的时间段返回响应或请求超时。
  3. 如果请求超时,则重复请求。
  4. 继续重复请求,直到收到响应(不必为 200 OK(或达到最大重试次数。
  5. 如果达到最大重试次数,那么我必须知道它,以便我可以记录错误。

我一直在玩:

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);
}

到目前为止,我只做了有限的测试,但它似乎工作正常。

如何创建将在超时后重新发送 HTTP 请求的可观察序列

要发送请求、设置请求超时并使用取消令牌,您可以将其包装到如下方法中:

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 方法可以有效地阻止调用线程的执行,直到结果可用,这是您在使用异步代码时想要做的事情。也许您有一些特定的场景,这就是为什么我在我的示例中将其留在那里的原因。