HttpClient4.4 进行Http连接通讯
以前一直使用jdk自带的urlConnection来进行http通讯,HttpClient与之相比,HttpClient更具有灵活度和易用性。HttpClient能够方便使用连接池,使用时需要重新创建连接,耗费巨大的连接时间。
HTTP协议
目前Http协议版本为1.1班,支持长连接,j2ee支持get,put,post,option,等方法。
- HTTP请求头
GET /link?url=chDeV_MryviuBdyQlKlkh0KwL0T4zzEU2jxSeOz2yD8ZPthCpAgRRufNz_4IKFP0AYKVcMkt2fLCmDsQ5a6m6p0PN1IcRz7KIN4R0ONTMrN97rr2JaH0bnFMD-M3Q1eX7W4b-5o-t96AIbNBOP_X05rXjAuw8bX-uNf_I3jPXAe HTTP/1.1
Host: baike.baidu.com
User-Agent: Mozilla/5.0 (Windows NT 5.1; rv:38.0) Gecko/20100101 Firefox/38.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
DNT: 1
Referer: http://www.baidu.com/link?url=chDeV_MryviuBdyQlKlkh0KwL0T4zzEU2jxSeOz2yD8ZPthCpAgRRufNz_4IKFP0AYKVcMkt2fLCmDsQ5a6m6p0PN1IcRz7KIN4R0ONTMrN97rr2JaH0bnFMD-M3Q1eX7W4b-5o-t96AIbNBOP_X05rXjAuw8bX-uNf_I3jPXAe&wd=&eqid=9adadb00000108a800000004555ea3a9
Cookie: bdshare_firstime=1423034727932; BIDUPSID=06ACBFD888B048E65E5EE3B6B3409EC8; BDUSS=XZtbDJ5eUZrcjNJTn5oTlF4dHFQQnVHbkt0TUJxZ1YwcEd4QndweW5KVWpsRzVWQVFBQUFBJCQAAAAAAAAAAAEAAACyEbBHem91cWYyMDA3AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACMHR1UjB0dVa; ATS_PASS=9; locale=zh; BAIDUID=F3A2EE0D70C7D935C8A2F1505F627F7D:FG=1; BDRCVFR[gltLrB7qNCt]=mk3SLVN4HKm; re__f=%20; BDRCVFR[2hu4KsUxzef]=mk3SLVN4HKm; BDRCVFR[i7zL5H8GeBs]=mk3SLVN4HKm; BDRCVFR[EJVTmGcXpQm]=mk3SLVN4HKm; H_PS_PSSID=1466_14335_13518_13075_10812_12868_14167_13692_10562_12723_14156_14173_14329_12038_13937_14177_8498_14194
Connection: keep-alive
- HTTP响应头
HTTP/1.1 200 OK
Server: JSP3/2.0.7
Date: Fri, 22 May 2015 06:11:46 GMT
Content-Type: text/css
Content-Length: 310
Connection: keep-alive
Etag: "1886989"
Last-Modified: Thu, 21 May 2015 01:38:06 GMT
Expires: Sat, 20 Jun 2015 06:48:35 GMT
Age: 84175
Cache-Control: max-age=2592000
Access-Control-Allow-Origin: *
Accept-Ranges: bytes
Vary: Accept-Encoding
Content-Encoding: gzip
HttpClient
- HttpClient通讯示例
public class HttpTranfer {
/* 定义日志管理器 */
private final static Logger logger = Logger.getLogger(HttpTranfer.class);
/* Http连接池只需要创建一个,因此采用单例模式的饿汉模式 */
private static PoolingHttpClientConnectionManager httpPoolManager = null;
/* HttpClient */
private CloseableHttpClient httpClient = null;
/* 连接池最大生成连接数200 */
private static int Pool_MaxTotal = 0;
/* 连接池默认路由最大连接数,默认为20 */
private static int Pool_MaxRoute = 0;
/* 请求超时时间 */
private static int Request_TimeOut = 0;
/*文件地址*/
private String fileUrl;
/*判断返回的是字符串还是数据流*/
private boolean isString = true;
/* 连接池参数配置 */
static {
/*连接池总的最大生成连接数500 */
Pool_MaxTotal = 500;
/* 连接池每个路由的最大连接数,默认为20 */
Pool_MaxRoute = 100;
/* 请求超时时间 60 * 1000 */
Request_TimeOut = 60000;
/* 创建连接池 */
if (httpPoolManager == null) {
/* 初始化连世界管理器 */
httpPoolManager = new PoolingHttpClientConnectionManager();
// 连接池总的最大生成连接数
httpPoolManager.setMaxTotal(Pool_MaxTotal);
// 设置每个route最大连接数
httpPoolManager.setDefaultMaxPerRoute(Pool_MaxRoute);
}
}
/**
* 创建HttpClient
* */
public HttpClient getHttpClient() {
CookieStore cookieStore = new BasicCookieStore();
CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
RequestConfig defaultRequestConfig = RequestConfig
.custom()
.setConnectTimeout(Request_TimeOut)
.setConnectionRequestTimeout(Request_TimeOut)
.setSocketTimeout(Request_TimeOut)
.setCookieSpec(CookieSpecs.DEFAULT)
.setExpectContinueEnabled(true)
.setTargetPreferredAuthSchemes(
Arrays.asList(AuthSchemes.NTLM, AuthSchemes.DIGEST))
.setProxyPreferredAuthSchemes(Arrays.asList(AuthSchemes.BASIC))
.build();
// 设置重定向策略
LaxRedirectStrategy redirectStrategy = new LaxRedirectStrategy();
// 创建httpClient
CloseableHttpClient httpClient = HttpClients.custom()
.setConnectionManager(httpPoolManager)
.setDefaultCookieStore(cookieStore)
.setDefaultCredentialsProvider(credentialsProvider)
.setDefaultRequestConfig(defaultRequestConfig)
.setRedirectStrategy(redirectStrategy)
.build();
this.httpClient = httpClient;
return httpClient;
}
/**
* form的enctype=application/x-www-form-urlencoded或text/plain的posten通讯
*
* @throws IOException
* @throws ClientProtocolException
* */
public Object httpPostString(String url, HashMap<String, String> postMap)
throws ClientProtocolException, IOException {
long beginTime = System.currentTimeMillis();
/* 返回内容 */
Object returnContent = null;
/* 创建HttpPost */
HttpPost httpPost = new HttpPost(url);
/* 在header中添加token */
httpPost.setHeader("token", "puji");
/* 拼接Post传输参数 */
UrlEncodedFormEntity encoderFormData = formatData(postMap);
httpPost.setEntity(encoderFormData);
/* 执行post请求 */
CloseableHttpResponse httpResponse = (CloseableHttpResponse) getHttpClient()
.execute(httpPost);
/* 读取通讯返回的status code */
int responseStatus = httpResponse.getStatusLine().getStatusCode();
/* 若通讯正常 */
if (responseStatus == HttpStatus.SC_OK) {
/* 获取相应的消息实体 */
HttpEntity responsehttpEntity = httpResponse.getEntity();
/* 读取utf-8格式的返回内容 */
returnContent = getResponseData(responsehttpEntity);
logger.error(returnContent);
}
/* 关闭响应实体 */
httpResponse.close();
/* 关闭httpClient连接 */
closeHttpClient();
long endTime = System.currentTimeMillis();
/* post耗时时间 */
logger.error(String.format("===== post cost time =[%d] =====", endTime
- beginTime));
return returnContent;
}
/**
* form的multipart/form的posten通讯 multipart/form只能通过get方式传递参数
*
* @throws IOException
* @throws ClientProtocolException
*
* 目前该方法存在服务端无法接收到addPart提交的数据,需要进一步调试
* */
public Object httpPostStream(String url, HashMap<String, Object> postMap)
throws ClientProtocolException, IOException {
long beginTime = System.currentTimeMillis();
/* 返回内容 */
Object returnContent = null;
/* 创建HttpPost */
HttpPost httpPost = new HttpPost(url);
/* 在header中添加token */
httpPost.setHeader("token", "puji");
MultipartEntityBuilder multipartEntityBuilder = MultipartEntityBuilder
.create();
/* 拼接字符串,传输参数 */
if (postMap != null && !postMap.isEmpty()) {
Iterator<Entry<String, Object>> iterator = postMap.entrySet()
.iterator();
while (iterator.hasNext()) {
Entry<String, Object> entry = iterator.next();
String keyName = entry.getKey();
Object keyValue = entry.getValue();
ContentType contentType = ContentType.create("text/plain",
Consts.UTF_8);
/* 若是字符参数 */
if (keyValue instanceof String) {
StringBody stringBody = new StringBody((String) keyValue,
contentType);
multipartEntityBuilder.addPart(keyName, stringBody);
/* 文件参数 */
} else {
FileBody fileBody = new FileBody((File) keyValue);
multipartEntityBuilder.addPart(keyName, fileBody);
}
}
}
HttpEntity requestHttpEntity = multipartEntityBuilder.build();
httpPost.setEntity(requestHttpEntity);
/* 执行post请求 */
CloseableHttpResponse httpResponse = (CloseableHttpResponse) getHttpClient()
.execute(httpPost);
/* 读取通讯返回的status code */
int responseStatus = httpResponse.getStatusLine().getStatusCode();
/* 若通讯正常 */
if (responseStatus == HttpStatus.SC_OK) {
/* 获取相应的消息实体 */
HttpEntity responseHttpEntity = httpResponse.getEntity();
/* 读取utf-8格式的返回内容 */
returnContent = getResponseData(responseHttpEntity);
logger.error(returnContent);
}
/* 关闭响应实体 */
httpResponse.close();
/* 关闭httpClient连接 */
closeHttpClient();
long endTime = System.currentTimeMillis();
/* post耗时时间 */
logger.error(String.format("===== post cost time =[%d] =====", endTime
- beginTime));
return returnContent;
}
/**
* get通讯
*
* @throws IOException
* @throws ClientProtocolException
* */
public Object httpGet(String url) throws ClientProtocolException,
IOException {
long beginTime = System.currentTimeMillis();
/* 返回内容 */
Object returnContent = null;
/* 创建HttpGet */
HttpGet httpGet = new HttpGet(url);
/* 执行请求 */
CloseableHttpResponse httpResponse = (CloseableHttpResponse) getHttpClient()
.execute(httpGet);
// 获取响应状态码
int statusCode = httpResponse.getStatusLine().getStatusCode();
/* 通讯正常 */
if (statusCode == HttpStatus.SC_OK) {
/* 获得响应的消息实体 */
HttpEntity responseHttpEntity = httpResponse.getEntity();
/* 读取utf-8格式的返回内容 */
returnContent = getResponseData((HttpEntity) responseHttpEntity);
logger.error(returnContent);
}
/* 关闭响应实体 */
httpResponse.close();
/* 关闭httpClient连接 */
closeHttpClient();
long endTime = System.currentTimeMillis();
/* post耗时时间 */
logger.error(String.format("===== post cost time =[%d] =====", endTime
- beginTime));
return returnContent;
}
/* 拼接Post传输参数,并设定为utf-8,只支持拼接String的字符,不支持流模式 */
private UrlEncodedFormEntity formatData(HashMap<String, String> postMap)
throws UnsupportedEncodingException {
List<NameValuePair> nvps = new ArrayList<NameValuePair>();
if (postMap != null && !postMap.isEmpty()) {
Iterator<Entry<String, String>> iterator = postMap.entrySet()
.iterator();
while (iterator.hasNext()) {
Map.Entry<String, String> map = iterator.next();
String keyName = (String) map.getKey();
String keyValue = (String) map.getValue();
nvps.add(new BasicNameValuePair(keyName, keyValue));
}
}
UrlEncodedFormEntity uefEntity = new UrlEncodedFormEntity(nvps, "UTF-8");
return uefEntity;
}
/* 判断返回的http实体是字符串还是流,还是文件 */
private Object getResponseData(HttpEntity responseHttpEntity)
throws ParseException, IOException {
if (responseHttpEntity != null) {
Header contentType = responseHttpEntity.getContentType();
if (contentType != null) {
/* 若是数据流 */
if (contentType.getValue().indexOf("application/octet-stream") >= 0) {
isString = false;
InputStream inputStream = responseHttpEntity.getContent();
/*数据流处理*/
File file = doInputStream(inputStream);
EntityUtils.consume(responseHttpEntity);
return file;
} else {
/* 对返回的内容进行编码 */
String responseContent = EntityUtils.toString(
responseHttpEntity, "UTF-8");
EntityUtils.consume(responseHttpEntity);
return responseContent;
}
} else {
return null;
}
} else {
return null;
}
}
/*返回数据流处理*/
private File doInputStream(InputStream inputStream) throws IOException{
int size = 0;
byte[] buffer = new byte[4096];
if(fileUrl != null && fileUrl.length() > 0){
File file = new File(fileUrl);
FileOutputStream fileOutputStream = new FileOutputStream(file);
while((size = inputStream.read(buffer)) != -1){
fileOutputStream.write(buffer, 0, size);
}
fileOutputStream.close();
inputStream.close();
return file;
}else{
while((size = inputStream.read(buffer)) != -1){}
inputStream.close();
return null;
}
}
/*关闭客户端*/
private void closeHttpClient() throws IOException {
//httpClient.close();
}
/*设定文件地址*/
public void setFileUrl(String fileUrl){
this.fileUrl = fileUrl;
}
/*判断返回的是字符串还是数据流*/
public boolean isString(){
return this.isString;
}
}
PoolingHttpClientConnectionManager连接池中HttpClient默认的路由参数为2个,默认的最大连接数为20个。连接池中路由的概念就是客户端连接到目标服务器的通道。比如client 连接到 目标服务器A 和client连接到目标服务器B,表示client 有两个路由通道。如果是单台目标服务器连接池中的路由最大连接参数参数和最大连接数可以设置一致。
若是多台目标服务器,PoolingHttpClientConnectionManager中的每个路由连接数参数不能过小,否则即使最大连接数设置很大,但是每个路由连接参数偏小,仍然无法实现并发效果。比如按照默认设定连接池参数,目标服务器为一个,那么最大并发连接数只能为2个,那么剩下的18个连接只能空闲等待,并非为这台目标服务器工作。
Servlet3.0后台接收文件
要实现Servlet 3.0的原生态文件上传支持,需要配置@MultipartConfig注解。配置完毕后,可以通过request.getPart(“inputName”)接收上传文件。若是多文件上传可以通过遍历request.getParts()接收文件。
1、@MultipartConfig有四个属性
fileSizeThreshold:当数据量大于该值时,内容将被写入文件。
location:存放生成的文件地址。当调用完write()方法后,自动删除该地址文件
maxFileSize:允许上传的文件最大值。默认值为 -1,表示没有限制。
maxRequestSize:针对该 multipart/form-data 请求的最大数量,默认值为 -1,表示没有限制。
2、通过getPart()或getParts()接收上传文件
/*服务端遍历所有上传数据*/
try {
/*文件存储路径*/
String path = "/home/files";
Iterator<Part>iterator=request.getParts().iterator();
while (iterator.hasNext()) {
Part part = (Part) iterator.next();
String partName = part.getName(); /*若是input的name属性含有file 表示是file域, name属性在客户端中根据value类型设定*/
if(partName.indexOf("file") >= 0){
/*获取文件名*/
String header = part.getHeader("content-disposition");
String fileName = header.substring(header.indexOf("filename=\"") + 10, header.lastIndexOf("\""));
String filePath = path + fileName;
part.write(filePath)
}else{
/*输出字符串参数*/
String value = "";
InputStream inputStream = part.getInputStream();
InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "UTF-8");
BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
while ((value += bufferedReader.readLine()) != null) {}
System.out.println("________________value="+value);
}
}
}catch (Exception e) {
e.printStackTrace();
}
指定文件接收路径也可以通过@MultipartConfig(location="/home/files")方式来指定
1、request.getParameter("name") 可以获取到通过addTextBody()方法添加的String类型的数据 。
2、request.getPart("name") 可以获取到通过addPart()、addBinaryBody()、addTextBody()添加的数据,返回类型为Part。
3、request.getParts() 得到Collection<Part>类型对象,可以接受addBinaryBody()、addPart()、addTextBody()添加的数据。
4、上面接收文件也可以通过FileOutputStream 接收
private void write(String fileName, InputStream in, String path)
throws IOException, FileNotFoundException {
OutputStream out = new FileOutputStream(filePath + filename);
byte[] buffer = new byte[1024];
int length = -1;
while ((length = in.read(buffer)) != -1) {
out.write(buffer, 0, length);
}
in.close();
out.close();
}
Servletf服务端返回文件流
String url = "D:\\rrtong\\xvid1.h";
File file = new File(url);
String fileName = file.getName();
int fileSize = (int) file.length(); /*定义返回的编码*/
response.setStatus(200); /*定义编码格式*/
response.setCharacterEncoding("UTF-8"); /*定义内容类型,application/octet-stream表示通用类型*/
response.setContentType("application/octet-stream; charset=utf-8"); /*定义返回文件名称*/
response.setHeader("Content-disposition", "attachment; filename="+ fileName); /*定义文件长度*/
response.setIntHeader("Content_Length", fileSize); /*生成文件流*/
InputStream fileInputStrream = new FileInputStream(file); OutputStream outputStream = response.getOutputStream(); /*输出文件流*/
int byteSize = 0;
byte arrByte[] = new byte[1024];
while((byteSize = fileInputStrream.read(arrByte)) != -1){
outputStream.write(arrByte,0, byteSize);
}
outputStream.flush();
fileInputStrream.close();
outputStream.close();
- 参考资料
http://backend.blog.163.com/blog/static/2022941262014029105618173/
http://niuzhenxin.iteye.com/blog/2100100
http://www.yeetrack.com/?p=773
http://hc.apache.org/httpcomponents-client-4.4.x/httpclient/apidocs/org/apache/http/client/methods/CloseableHttpResponse.html
http://blog.csdn.net/fengyuzhengfan/article/details/39941851
http://www.cppblog.com/iuranus/archive/2010/07/04/119311.html
http://www.yeetrack.com/?p=773
http://www.yeetrack.com/?p=782
http://www.yeetrack.com/?p=822
http://www.yeetrack.com/?p=825
http://www.yeetrack.com/?p=832
http://www.yeetrack.com/?p=844
HttpClient4.4 进行Http连接通讯的更多相关文章
- Netty实现服务端客户端长连接通讯及心跳检测
通过netty实现服务端与客户端的长连接通讯,及心跳检测. 基本思路:netty服务端通过一个Map保存所有连接上来的客户端SocketChannel,客户端的Id作为Map的key.每 ...
- SignalR代理对象异常:Uncaught TypeError: Cannot read property 'client' of undefined 推出的结论 SignalR 简单示例 通过三个DEMO学会SignalR的三种实现方式 SignalR推送框架两个项目永久连接通讯使用 SignalR 集线器简单实例2 用SignalR创建实时永久长连接异步网络应用程序
SignalR代理对象异常:Uncaught TypeError: Cannot read property 'client' of undefined 推出的结论 异常汇总:http://www ...
- 【WebSocket No.1】实现服务端webSocket连接通讯
前言 现阶段socket通信使用TCP.UDP协议,其中TCP协议相对来说比较安全稳定!本文也是来讲解TCP为主(恕在下学艺不精). 下面是个人理解的tcp/ip进行通讯之间的三次握手! 1.客户端先 ...
- SICK激光扫描仪LMS511连接通讯
一.设备介绍: 型号:LMS511-10100(DC 24v) 品牌:SICK 操作环境:Windows 10 64bit 软件:SOPAS ET 连接线:串口转网口线(1根/4针 子头),电源线( ...
- 通过netty实现服务端与客户端的长连接通讯,及心跳检测。
基本思路:netty服务端通过一个Map保存所有连接上来的客户端SocketChannel,客户端的Id作为Map的key.每次服务器端如果要向某个客户端发送消息,只需根据ClientId取出对应的S ...
- android BLE Peripheral 做外设模拟设备,供ios、android 连接通讯。
为了能让其它设备可以发现其设备,先启动特定广播.看自己需要什么广播格式. 对于广播可见的mac address: 在调用startAdvertising();时,mac address 就会改变. 并 ...
- linux c TCP连接通讯
服务端: 1.申请服务端自己的socket 2.对addr赋值 3.bind文件描述符和地址信息 4.listen监听服务 5.等待accept客户端的连接 6.处理建立好的连接 7.关闭socket ...
- Pushlet浏览器长连接通讯
原文链接:http://cuisuqiang.iteye.com/blog/1416771 Pushlet(一种comet 架构的实现)是基于Servlet 机制,数据从server端的Java 对象 ...
- Android 蓝牙4.0的连接和通讯
1.加入权限 <uses-sdk android:minSdkVersion=" android:targetSdkVersion="/> <uses-featu ...
随机推荐
- 我的第一个Struts程序
1.程序结构 2.各种文件 LoginAction.java package com.tfj.action; public class LoginAction { private String use ...
- bzoj3262
三维裸的做法是一维排序,剩下树套树,可我好像还没写过树套树先说cdq分治吧,先对一维排序,相当于原来修改询问里的时间线在这上面分治.划分,计算前半部分对后半部分的影响,显然可以按第二维的顺序维护树状数 ...
- js 获取服务器控件
大致是HtmlControl被服务器发送到页面ID不变,比如<div id="a" runat="sever"></div> WebCo ...
- MyEclipse常用操作技巧
1.源码和帮助文档的的关连 下面以关联struts2-core-2.3.14.2.jar源代码为例: 如下为示意图 2.拷贝项目的时候,要注意 将项目的web-root fold改成更新后的名字项目名 ...
- Apk修改利器:ApkToolkit v2.1
作 者: Mzucore 时 间: 2013-05-10, 17:18:23 链 接: http://www.unpack.cn/thread-93058-1-1.html 下载地址:http://b ...
- [Tommas] 如何创建自动化功能测试的基本原则
每个实行持续交付的项目,都有生产流水线的元素,如持续集成和自动化测试.这些测试是在不同层面进行的,从单元测试到冒烟测试再到功能测试.自动化功能测试的优点之一是可重复性和可预测的执行时间.出于这个原因, ...
- JZ2440开发笔记(1)——arm-linux-gcc环境搭建
1 下载arm-linux-gcc-4.4.3安装包,http://arm9.net/download.asp 2 解压arm-linux-gcc-4.4.3-20100728.tar.gz,使用命令 ...
- c++ 11 key note
*:first-child { margin-top: 0 !important; } body > *:last-child { margin-bottom: 0 !important; } ...
- aix 系统运行级别
运行级别 在操作系统上运行维护之前,或者修改系统运行级别之前,需检查各种不同的运行级别.运行级别是一个软件配置,只允许一组选定的进程存在. 识别系统运行级别 本节描述如何识别系统正运行在什么样的运行级 ...
- HW4.11
public class Solution { public static void main(String[] args) { int count = 0; for(int i = 100; i & ...