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.sys
和 HttpListener
在内部完成的?
是的。 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请求