【问题标题】:HttpClient pipelining HTTP GET requests to ServiceStack APIHttpClient 将 HTTP GET 请求流水线化到 ServiceStack API
【发布时间】:2015-11-06 07:49:50
【问题描述】:

首先,我将 ServiceStack 作为提供 RESTful HTTP API 的服务器。

这是一个例子。

public void GET(XXXXXRequest request)
{
    System.Threading.Thread.Sleep(2000);
}

然后我使用System.Net.Http.HttpClient 访问它。 正如here 所说,HttpClient 对于大多数通过同一 TCP 连接发送 HTTP GET 请求的方法都是线程安全的。

所以我有一个 HttpClient 的单例实例,如下所示

HttpClient _httpClient = new HttpClient(new WebRequestHandler()
{
    AllowPipelining = true
});

然后我使用以下测试代码在前一个响应之后发送请求

await _httpClient.SendAsync(request1, HttpCompletionOption.ResponseContentRead);
await _httpClient.SendAsync(request2, HttpCompletionOption.ResponseContentRead);
await _httpClient.SendAsync(request3, HttpCompletionOption.ResponseContentRead);

smart sniffer 中,我确实看到请求是在一个连接中发送的,它类似于:

Client -> Request1
Client <- Response1
Client -> Request2
Client <- Response2
Client -> Request3
Client <- Response3

现在我将代码更改为即发即弃模式,如下所示。

_httpClient.SendAsync(request1, HttpCompletionOption.ResponseContentRead);
_httpClient.SendAsync(request2, HttpCompletionOption.ResponseContentRead);
_httpClient.SendAsync(request3, HttpCompletionOption.ResponseContentRead);

这样请求就可以在不等待之前的响应的情况下发送,我期望请求和响应如下所示

Client -> Request1
Client -> Request2
Client -> Request3
Client <- Response1
Client <- Response2
Client <- Response3

这是HTTP pipeline,性能非常好。

但从我的测试中,我看到每个 HTTP GET 请求都建立了 3 个连接,但它没有按我的预期工作。

关于AllowPipelining proeprty,MSDN

应用程序使用 AllowPipelining 属性来指示 流水线连接的偏好。当 AllowPipelining 为真时,一个 应用程序与支持的服务器建立管道连接 他们。

那么,我想HttpClient 确实支持流水线,问题出在ServiceStack 中? ServiceStack 中是否有一些选项可以启用 HTTP 管道?

【问题讨论】:

    标签: servicestack dotnet-httpclient http.sys http-pipelining


    【解决方案1】:

    流水线在非常低的级别完成,甚至低于 IIS(在http.sys 内核模式驱动程序中)。虽然恐怕我无法解释您所看到的行为,但我可以自信地说,ServiceStack 不会支持它。它是一个HttpHandler,它只关心如何处理请求并返回响应。

    【讨论】:

    • 我使用的是自托管服务 AppSelfHostBase 而不是 IIS,我假设它是通过 http.sysHttpListener 在内部完成的?
    • 是的。 ServiceStack 的listener 在内部使用 System.Net.HttpListener。
    【解决方案2】:

    当你使用多个await操作符时,它们会一个接一个地运行,所以HttpClient一次只能得到一个请求,因此不能使用流水线。

    您可以使用 Task.WhenAll() 并行运行多个任务:

    var responses = await Task.WhenAll(
        _httpClient.SendAsync(request1, HttpCompletionOption.ResponseContentRead),
        _httpClient.SendAsync(request2, HttpCompletionOption.ResponseContentRead),
        _httpClient.SendAsync(request3, HttpCompletionOption.ResponseContentRead));
    
    var response1 = responses[0];
    var response2 = responses[1];
    var response3 = responses[2];
    

    请注意,只有 Task.WhenAll 处于等待状态

    【讨论】:

      猜你喜欢
      • 2011-07-04
      • 1970-01-01
      • 1970-01-01
      • 2015-02-02
      • 1970-01-01
      • 1970-01-01
      • 2015-05-18
      • 2019-10-12
      • 1970-01-01
      相关资源
      最近更新 更多