System.Net.Http.HttpClient 类用于发送 HTTP 请求以及从 URI 所标识的资源接收 HTTP 响应。 HttpClient 实例是应用于该实例执行的所有请求的设置集合,每个实例使用自身的连接池,该池将其请求与其他请求隔离开来。 从 .NET Core 2.1 开始,SocketsHttpHandler 类提供实现,使行为在所有平台上保持一致。
HttpClient实例是执行网络请求的设置集合,每个实例会使用一个连接池。通过这段描述我们知道实际使用HttpClient的时候我们只需要实例化一个就行了,在处理程序实例内池连接,并在多个请求之间重复使用连接。也就是官方提倡的使用单个实例,如果每次请求就实例化一个HttpClient,则会创建不必要的连接降低性能,并且TCP 端口不会在连接关闭后立即释放。
所以如果是大批量创建HttpClient请求则大量负载下可用的套接字数将耗尽,这种耗尽将导致 SocketException 错误。
static readonly HttpClient httpClient = new HttpClient();
public class HttpClientInstance
{
private static readonly HttpClient \_HttpClient;
static HttpClientInstance()
{
_HttpClient = new HttpClient();
}
public static HttpClient GetHttpClient()
{
return _HttpClient;
}
}
可以通过构造参数(如 HttpClientHandler (或 SocketsHttpHandler .NET Core 2.1 或更高版本) )作为构造函数的一部分来配置其他选项。 实例化HttpClient后无法更连接属性,因此,如果需要更改连接属性,则需要创建新的 HttpClient 实例。
配置可以在构造期间配置 HttpClientHandler 或 SocketsHttpHandler 传入,SocketsHttpHandler可以设置额外参数包括 MaxConnectionsPerServer, PooledConnectionIdleTimeout、PooledConnectionLifetime、ConnectTimeout。
var handler = new SocketsHttpHandler
{
PooledConnectionLifetime = TimeSpan.FromMinutes(15)
};
var httpClient = new HttpClient(handler);
在.NET Framework 只能使用HttpClientHandler
,且没有PooledConnectionIdleTimeout和PooledConnectionLifetime等参数。
HttpClientHandler httpClientHandler = new HttpClientHandler();
//最大并发连接数
httpClientHandler.MaxConnectionsPerServer = 100;
HttpClient httpClient=new HttpClient(httpClientHandler);
//超时设置
httpClient.Timeout = new TimeSpan(5000);
可以是设置MaxConnectionsPerServer,可以设置Timeout
。Timeout 为来自 HttpClient 实例的所有 HTTP 请求设置默认超时。 超时仅适用于导致启动请求/响应的 xxxAsync 方法。 如果达到超时,则会 Task<TResult> 取消该请求。这个超时时间是包含从请求到响应的整个时间段,而不像上面参数可以设置连接超时。
##请求实现
HttpClient这是一个高级 API,用于包装其运行的每个平台上可用的较低级别功能。
在每个平台上, HttpClient 尝试使用最佳可用传输:
在上面实现可以看到在不同的框架下HttpClient的实现是不一样的,在.NET Framework下是使用HttpWebRequest
支持。
所以还会受限HttpWebRequest的实现,如果我们要启用多线程高频率调用接口,那么这里要注意HttpWebRequest的连接并发的数量限制。HttpWebRequest通过ServicePoint设置,我们通过反编译看到HttpWebRequest构造函数。
ServicePoint.DefaultConnectionLimit获取允许的最大并发连接数。 对于 ASP.NET 托管的应用程序,默认连接限制为 10,对于所有其他应用程序,默认连接限制为 2。DefaultConnectionLimit 对现有 ServicePoint 对象没有影响;它只影响更改后初始化的对象。如果未直接或通过配置设置此属性的值,则该值默认为常量 DefaultPersistentConnectionLimit
。
如果是应用连接池默认只有2个并发,所以当你启用很多线程的时候实际效率是不会提升的,一直只有两个并发在阻塞排队,如果请求比较耗时后面的请求还有异常的可能。
因此当你使用多线程的时候要注意初始化HttpClient的httpClientHandler.MaxConnectionsPerServer = n;
该参数用于设置。
平时我们可能使用RestSharp 用于网络请求,实际也是在HttpWebRequest上的封装,在官网我们可以看到如下说明:
在最新的v107换成了HttpClient,以前的版本也是HttpWebRequest。如果要设置RestSharp的连接池并发数需要修改默认值。
System.Net.ServicePointManager.DefaultConnectionLimit = n;
然后再实例化RestClient。