HttpClient 将 HTTP GET 请求流水线化到 ServiceStack API

Posted

技术标签:

【中文标题】HttpClient 将 HTTP GET 请求流水线化到 ServiceStack API【英文标题】:HttpClient pipelining HTTP GET requests to 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 管道?

【问题讨论】:

【参考方案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 处于等待状态

【讨论】:

以上是关于HttpClient 将 HTTP GET 请求流水线化到 ServiceStack API的主要内容,如果未能解决你的问题,请参考以下文章

HttpClient 将 HTTP GET 请求流水线化到 ServiceStack API

Android--httpclient模拟post请求和get请求

httpclient如何发送get请求

新手求助,Arduino联网后,如何回应HttpClient的GET请求

java HttpClient GET请求

HttpClient中带参数的get请求