在.Net 4.0之前,一直是依靠HttpWebRequest实现Http操作的。它默认有一个非常保守的同一站点下最大2并发数限制,导致默认情况下HttpWebRequest往往得不到理想的速度,必须修改App.config或ServicePointManager.DefaultConnectionLimit的值。所以对于需要高并发请求的场景HttpWebRequest不是一个理想的选择。

MS在.Net 4.5中引入了一个HttpClient类专门处理Http操作,HttpClient不受HttpWebRequest并发策略控制,也没有系统级的并发限制。

关于HttpClient和HttpWebRequest的一些区别参考(https://stackoverflow.com/questions/22214930/httpclient-vs-httpwebrequest)

下面开始进入重点,在本文之前对于HttpClient有过很多错误的使用,最开始使用的如下代码:

写一个静态方法,每次调用该方法都会new一个新的HttpClient对象,使用完成后释放HttpClient对象

        public static HttpResponseMessage GetRequest(string requestUri, string accessToken)
{
using (HttpClient client = new HttpClient())
{
if (!string.IsNullOrEmpty(accessToken))
{
client.DefaultRequestHeaders.Add("Authorization", "Bearer " + accessToken);
}
client.DefaultRequestHeaders.Add("Accept", "application/json");
try
{
var response = client.GetAsync(requestUri).Result;
if (response.IsSuccessStatusCode)
{
return response;
}
else
{
throw new Exception(response.Content.ReadAsStringAsync().Result);
}
}
catch (Exception ex)
{ throw ex;
}
}
}

那这就完成没有发挥出HttpClient的一大优势(同一HttpClient可以发送多个请求),而以上代码一个请求就会创建一个HttpClient对象,同时我们调用HttpClient的Dispose()方法销毁它时,它就启动一个进程,关闭在它控制之下的套接字。也就是说,你下次请求连接时,必须重复整个连接新建过程。如果网络延迟很高,或者连接是受保护的(需要新一轮的SSL/TLS协商),就会非常痛苦。

所以HttpClient关闭套接字的过程并不快。当“关闭”套接字时,你真正做的是将TCP连接状态置为TIME_WAIT。在一个预先配置好的时间窗口内,Windows将保持该套接字的状态不变,默认情况下是4分钟。这是为了防止有任何剩余的数据包仍在传输。

所以以上代码是一个错误的使用方式,如果在一个高并发场景,服务器资源也会迅速耗尽。

所以我们的正确做法应该是:HttpClient应该只初始化一次,并在应用程序的整个生存期内重用。在负载很高的情况下,为每个请求初始化一个HttpClient类会耗尽可用的套接字数量。

以下展示正确的做法,就是对HttpClient做单例处理,使得应用生命周期内只有一个HttpClient对象,并可以重用,并且不调用Dispose()方法。

    internal class HttpClientUtils
{
private static HttpClient _httpClient;
private readonly static object _lock = new object();
private readonly static HttpClientUtils _httpClientUtils = new HttpClientUtils(); static HttpClientUtils()
{
_httpClient = GetHttpClient();
} public static HttpClientUtils GetHttpClientUtils()
{
return _httpClientUtils;
} private HttpClientUtils()
{
} private static HttpClient GetHttpClient()
{
lock (_lock)
{
if (_httpClient == null)
{
_httpClient = new HttpClient();
//_httpClient.DefaultRequestHeaders.Add("Accept", "application/json");
_httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
_httpClient.Timeout = TimeSpan.FromSeconds();
}
}
return _httpClient;
}
}

以上代码解决了HttpClient重用问题,但是竟然所有Http请求都使用同一HttpClient对象,那么新的问题也随之而来,可能我们会遇到不同的HttpClient请求需要带不同的Http请求头,

那么如下所示代码,就会造成很大问题,因为并不是所有的Http请求都需要此请求头。

client.DefaultRequestHeaders.Add("Accept", "application/json");
//....

那么问题的关键就在于,我们不能将请求头直接赋值到HttpClient对象的DefaultRequestHeaders属性上。

那么应该如何讲请求头和HttpClient对象分离。我们可以使用SendAsync(HttpRequestMessage request); ,在HttpRequestMessage中添加请求头。

以Get请求为例,示例如下:

        public async Task<HttpResponseMessage> GetRequestAsync(string requestUri, string accessToken)
{
HttpRequestMessage message = new HttpRequestMessage(HttpMethod.Get, requestUri);
if (!string.IsNullOrEmpty(accessToken))
{
message.Headers.Add("Authorization", "Bearer " + accessToken);
}
try
{
var response = await _httpClient.SendAsync(message);
//var response = await this._client.GetAsync(requestUri);
if (response.IsSuccessStatusCode)
{
return response;
}
else
{
throw new Exception(response.Content.ReadAsStringAsync().Result);
}
}
catch (Exception ex)
{
throw ex;
}
}

可以看到我们将Http请求方法,Http请求Url以及请求头信息,封装到HttpRequestMessage对象中,使用 SendAsync(HttpRequestMessage request); 发送请求

而这正好解决高并发下Http请求发送的问题,避免不同Http请求互相造成干扰。

使用HttpClient实现并发请求的更多相关文章

  1. 对tomcat7模拟并发请求及相关配置参数的含义

    这里的并不是真正的并发请求,因为for循环是间隔10毫秒,并且线程初始化也需要时间的,到真正执行http请求的时刻是不确定的.  tomcat 的运行状态可以在webapps下的manage项目查看, ...

  2. httpclient的并发连接问题

    昨天的搜索系统又出状况了,几个库同时重建索引变得死慢.经过一个上午的复现分析,确定问题出现httpclient的使用上(我使用的是3.1这个被广泛使用的遗留版本).搜索系统在重建索引时,是并发多个线程 ...

  3. 170314、工具:apache httpClient多线程并发情况下安全实用及工具类分享

    简单用法介绍:介绍来源网络 建立连接:在HttpClient中使用多线程的一个主要原因是可以一次执行多个方法.在执行期间,每一个方法都使用一个HttpConnection实例.由于在同一时间多个连接只 ...

  4. 如何配置IIS处理多并发请求及存在的问题

    很多时候多线程能快速高效独立的计算数据,应用比较多. 但今天遇到的多进程下的问题更是让人觉得复杂 多进程下static变量都要失效,就目前的平台和产品static使用是很多的,各种session.ca ...

  5. 查看 Apache并发请求数及其TCP连接状态

    查看 Apache并发请求数及其TCP连接状态 (2011-06-27 15:08:36) 服务器上的一些统计数据: 1)统计80端口连接数 netstat -nat|grep -i "80 ...

  6. 查看 并发请求数及其TCP连接状态【转】

    服务器上的一些统计数据: 1)统计80端口连接数netstat -nat|grep -i "80"|wc -l 2)统计httpd协议连接数ps -ef|grep httpd|wc ...

  7. HttpClientUtil [使用apache httpclient模拟http请求]

    基于httpclient-4.5.2 模拟http请求 以get/post方式发送json请求,并获取服务器返回的json -------------------------------------- ...

  8. IIS处理并发请求时出现的问题及解决

    一个ASP.NET项目在部署到生产环境时,当用户并发量达到200左右时,IIS出现了明显的请求排队现象,发送的请求都进入等待,无法及时响 应,系统基本处于不可用状态.因经验不足,花了很多时间精力解决这 ...

  9. Web大规模高并发请求和抢购的解决方案

    电商的秒杀和抢购,对我们来说,都不是一个陌生的东西.然而,从技术的角度来说,这对于Web系统是一个巨大的考验.当一个Web系统,在一秒钟内收到数以万计甚至更多请求时,系统的优化和稳定至关重要.这次我们 ...

随机推荐

  1. SpringMVC中fastjson支持jsonp的实现

    前边一篇文章主要说了下前端处理jsonp的方式,这篇主要介绍了后台接收和响应jsonp的一种方式 继承fastjson消息转换器类:com.alibaba.fastjson.support.sprin ...

  2. appium运行报错java.net.SocketException: socket write error

    这个错我调了 快两天一点头绪没有,脚本正常跑没问题,但是就是控制台输出信息报错,没法定位问题在哪.报错如图: 虽然这个报错不影响测试结果,但是本人有强迫症,一定要查出究竟: 我的尝试: 1.那天试验, ...

  3. Java中日期格式化SimpleDateFormat类包含时区的处理方法

    1.前言 需要把格式为“2017-02-23T08:04:02+01:00”转化成”23-02-2017-T15:04:02“格式(中国时区为+08:00所以是15点),通过网上查找答案,发现没有我需 ...

  4. X-Forwarded-For 的一些理解

    X-Forwarded-For 是一个 HTTP 扩展头部, 主要是为了让 Web 服务器获取访问用户的真实 IP 地址(其实这个真实未必是真实的,后面会说到). 那为什么 Web 服务器只有通过 X ...

  5. hibernate 多对一(级联)操作

    级联:当你存储一个表的内容想值得相关联的表也存储数据时,可以通过级联来实现(cascade)@Entity@Table(name="t_User")public class Use ...

  6. Linux权限命令

    Linux 基础——权限管理命令chmod   一.Linux中的文件权限与目录权限 Linux中定义了3种访问权限,分别是r.w.x.其中r表示对象是可读的,w表示对象是可写的,x表示对象是可执行的 ...

  7. JVM启动过程 类加载器

    下图来自:http://blog.csdn.net/jiangwei0910410003/article/details/17733153 package com.test.jvm.common; i ...

  8. -webkit-line-clamp超出省略

    以前只用过超出一行显示省略号 有时候会碰到只显示两到三行,超出省略 -webkit-line-clamp属性就能解决这个问题 text-overflow: -o-ellipsis-lastline; ...

  9. Python swapcase

    swapcase 字符串大写转换为小写小写转换为大写. a = "woHaoshuai" a.swapcase() WOhAOSHUAI

  10. 51Nod 算法马拉松28 B题 相似子串 哈希

    欢迎访问~原文出处——博客园-zhouzhendong 去博客园看该题解 题目传送门 - 51Nod1753 题意概括 两个字符串相似定义为: 1.两个字符串长度相等 2.两个字符串对应位置上有且仅有 ...