httpclient的一些学习心得
最近忙于一个项目,了解下httpclient,在这里总结出来,和大家一起学习分享,希望各位朋友提出宝贵的意见。
首先介绍一下项目的背景:
目标:把国内一家保险公司的“WEB一账通”改成“WAP一账通”。
资源:客户不提供任何的webservice接口。
本项目中用到的第三方组件是apache的httpclient,一个非常强大的网页抓取工具(抓这个字用得可能不太好), 这里和大家
一起讨论下httpclient的一些常用用法和要注意的地方。
本文引用的资源列表:
httpclient入门: http://www.ibm.com/developerworks/cn/opensource/os-httpclient/
httpclient证书导入:http://www.blogjava.net/happytian/archive/2006/12/22/89447.html
httpclient高级认识:http://laohuang.iteye.com/blog/55613
httpclient官方文档:http://hc.apache.org/httpcomponents-client/index.html
httpclient资源关闭:http://www.iteye.com/topic/234759
上面的文章写得很好,看完之后也就知道怎么用httpclient这个很好的工具了,但是在这里还是补充一些比较重要的东西,也是项目中经
常碰到的问题。
首先要注意的有以下几点:
1、httpclient连接后资源释放问题很重要,就跟我们用database connection要释放资源一样。
2、https网站采用ssl加密传输,证书导入要注意。
3、做这样的项目最好先了解下http协义,比如302,301,200,404返回代码的含义(这是最基本的),cookie,session的机制。
4、httpclient的redirect状态默认是自动的,这在很大程度上给开发者很大的方便(如一些授权获得cookie),但是有时要手动管理下,比如
有时会遇到CircularRedirectException异常,出现这样的情况是因为返回的头文件中location值指向之前重复(端口号可以不同)地址,导致可能会出现死
循环递归重定向,这时可以手动关闭:method.setFollowRedirects(false)
5、有的网站会先判别用户的请求是否是来自浏览器,如不是,则返回不正确的文本,所以用httpclient抓取信息时在头部加入如下信息:
header.put("User-Agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; QQDownload 1.7; .NET CLR 1.1.4322; CIBA; .NET CLR 2.0.50727)");
6、当post请求提交数据时要改变默认编码,不然的话提交上去的数据会出现乱码。重写postMethod的setContentCharSet()方法就可以了:
下面写一个通用类来处理request请求返回的文本:
/*
* HttpRequestProxy.java
*
* Created on November 3, 2008, 9:53 AM
*/
package cn.com.mozat.net;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import org.apache.commons.httpclient.Header;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpException;
import org.apache.commons.httpclient.HttpMethod;
import org.apache.commons.httpclient.NameValuePair;
import org.apache.commons.httpclient.SimpleHttpConnectionManager;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.httpclient.methods.PostMethod;
import cn.com.mozat.exception.CustomException;
/**
*
* @author bird email:lihongfu-84@163.com
*
* 2008-11-4 09:49:48
*/
public class HttpRequestProxy{
//超时间隔
private static int connectTimeOut = 60000;
//让connectionmanager管理httpclientconnection时是否关闭连接
private static boolean alwaysClose = false;
//返回数据编码格式
private String encoding = "UTF-8";
private final HttpClient client = new HttpClient(new SimpleHttpConnectionManager(alwaysClose));
public HttpClient getHttpClient(){
return client;
}
/**
* 用法:
* HttpRequestProxy hrp = new HttpRequestProxy();
* hrp.doRequest("http://www.163.com",null,null,"gbk");
*
* @param url 请求的资源URL
* @param postData POST请求时form表单封装的数据 没有时传null
* @param header request请求时附带的头信息(header) 没有时传null
* @param encoding response返回的信息编码格式 没有时传null
* @return response返回的文本数据
* @throws CustomException
*/
public String doRequest(String url,Map postData,Map header,String encoding) throws CustomException{
String responseString = null;
//头部请求信息
Header[] headers = null;
if(header != null){
Set entrySet = header.entrySet();
int dataLength = entrySet.size();
headers= new Header[dataLength];
int i = 0;
for(Iterator itor = entrySet.iterator();itor.hasNext();){
Map.Entry entry = (Map.Entry)itor.next();
headers[i++] = new Header(entry.getKey().toString(),entry.getValue().toString());
}
}
//post方式
if(postData!=null){
PostMethod postRequest = new PostMethod(url.trim());
if(headers != null){
for(int i = 0;i < headers.length;i++){
postRequest.setRequestHeader(headers[i]);
}
}
Set entrySet = postData.entrySet();
int dataLength = entrySet.size();
NameValuePair[] params = new NameValuePair[dataLength];
int i = 0;
for(Iterator itor = entrySet.iterator();itor.hasNext();){
Map.Entry entry = (Map.Entry)itor.next();
params[i++] = new NameValuePair(entry.getKey().toString(),entry.getValue().toString());
}
postRequest.setRequestBody(params);
try {
responseString = this.executeMethod(postRequest,encoding);
} catch (CustomException e) {
throw e;
} finally{
postRequest.releaseConnection();
}
}
//get方式
if(postData == null){
GetMethod getRequest = new GetMethod(url.trim());
if(headers != null){
for(int i = 0;i < headers.length;i++){
getRequest.setRequestHeader(headers[i]);
}
}
try {
responseString = this.executeMethod(getRequest,encoding);
} catch (CustomException e) {
e.printStackTrace();
throw e;
}finally{
getRequest.releaseConnection();
}
}
return responseString;
}
private String executeMethod(HttpMethod request, String encoding) throws CustomException{
String responseContent = null;
InputStream responseStream = null;
BufferedReader rd = null;
try {
this.getHttpClient().executeMethod(request);
if(encoding != null){
responseStream = request.getResponseBodyAsStream();
rd = new BufferedReader(new InputStreamReader(responseStream,
encoding));
String tempLine = rd.readLine();
StringBuffer tempStr = new StringBuffer();
String crlf=System.getProperty("line.separator");
while (tempLine != null)
{
tempStr.append(tempLine);
tempStr.append(crlf);
tempLine = rd.readLine();
}
responseContent = tempStr.toString();
}else
responseContent = request.getResponseBodyAsString();
Header locationHeader = request.getResponseHeader("location");
//返回代码为302,301时,表示页面己经重定向,则重新请求location的url,这在
//一些登录授权取cookie时很重要
if (locationHeader != null) {
String redirectUrl = locationHeader.getValue();
this.doRequest(redirectUrl, null, null,null);
}
} catch (HttpException e) {
throw new CustomException(e.getMessage());
} catch (IOException e) {
throw new CustomException(e.getMessage());
} finally{
if(rd != null)
try {
rd.close();
} catch (IOException e) {
throw new CustomException(e.getMessage());
}
if(responseStream != null)
try {
responseStream.close();
} catch (IOException e) {
throw new CustomException(e.getMessage());
}
}
return responseContent;
}
/**
* 特殊请求数据,这样的请求往往会出现redirect本身而出现递归死循环重定向
* 所以单独写成一个请求方法
* 比如现在请求的url为:http://localhost:8080/demo/index.jsp
* 返回代码为302 头部信息中location值为:http://localhost:8083/demo/index.jsp
* 这时httpclient认为进入递归死循环重定向,抛出CircularRedirectException异常
* @param url
* @return
* @throws CustomException
*/
public String doSpecialRequest(String url,int count,String encoding) throws CustomException{
String str = null;
InputStream responseStream = null;
BufferedReader rd = null;
GetMethod getRequest = new GetMethod(url);
//关闭httpclient自动重定向动能
getRequest.setFollowRedirects(false);
try {
this.client.executeMethod(getRequest);
Header header = getRequest.getResponseHeader("location");
if(header!= null){
//请求重定向后的URL,count同时加1
this.doSpecialRequest(header.getValue(),count+1, encoding);
}
//这里用count作为标志位,当count为0时才返回请求的URL文本,
//这样就可以忽略所有的递归重定向时返回文本流操作,提高性能
if(count == 0){
getRequest = new GetMethod(url);
getRequest.setFollowRedirects(false);
this.client.executeMethod(getRequest);
responseStream = getRequest.getResponseBodyAsStream();
rd = new BufferedReader(new InputStreamReader(responseStream,
encoding));
String tempLine = rd.readLine();
StringBuffer tempStr = new StringBuffer();
String crlf=System.getProperty("line.separator");
while (tempLine != null)
{
tempStr.append(tempLine);
tempStr.append(crlf);
tempLine = rd.readLine();
}
str = tempStr.toString();
}
} catch (HttpException e) {
throw new CustomException(e.getMessage());
} catch (IOException e) {
throw new CustomException(e.getMessage());
} finally{
getRequest.releaseConnection();
if(rd !=null)
try {
rd.close();
} catch (IOException e) {
throw new CustomException(e.getMessage());
}
if(responseStream !=null)
try {
responseStream.close();
} catch (IOException e) {
throw new CustomException(e.getMessage());
}
}
return str;
}
public static void main(String[] args) throws Exception{
HttpRequestProxy hrp = new HttpRequestProxy();
Map header = new HashMap();
header.put("User-Agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; QQDownload 1.7; .NET CLR 1.1.4322; CIBA; .NET CLR 2.0.50727)");
String str = hrp.doRequest("http://www.cma-cgm.com/en/eBusiness/Tracking/Default.aspx?BolNumber=GZ2108827", null, header,null);
System.out.println(str.contains("row_CRXU1587647"));
// System.out.println(str);
}
}
分享到:
相关推荐
以下是对HttpClient主要特性和使用方法的详细说明: 1. **协议支持**: HttpClient支持HTTP 1.0和1.1协议,并且可以通过Java Secure Socket Extension (JSSE)实现对Secure Sockets Layer (SSL)或Transport Layer ...
总结来说,httpclient.jar是Java开发中用于HTTP通信的强大工具,而code.jar则可能是项目中特定功能或扩展的代码集合。两者结合使用,可以构建出功能完善的HTTP客户端解决方案。理解和熟练掌握HttpClient库,将有助于...
### Httpclient官网教程中文版知识点总结 #### 一、引言 HTTP协议作为互联网的核心通信标准之一,在现代网络服务及物联网设备中扮演着至关重要的角色。随着技术的发展,越来越多的应用和服务依赖于HTTP协议来实现...
总结,HttpClient 4.2.1作为Java开发中的HTTP通信工具,不仅具备高效、稳定的特性,还提供了强大的功能,使得开发者能够轻松应对各种HTTP需求。无论是简单的GET请求还是复杂的POST操作,HttpClient都能游刃有余,为...
总结,`commons-httpclient-3.0.jar`在JAVA中的应用,不仅提供了一种简单易用的HTTP客户端实现,还具有丰富的特性和扩展性,对于理解和实现网络通信具有重要的学习价值。然而,随着技术的进步,开发者应关注并适时...
总结起来,这些jar包共同构成了一个完整的Java HttpClient环境,能够处理各种复杂的HTTP通信任务,从简单的GET和POST请求到复杂的文件上传、多部分表单数据处理,以及与Web服务器的高级交互。开发者可以根据项目需求...
总结,`httpclient-4.5.jar`及其相关依赖提供了全面的HTTP客户端功能,适用于各种Java应用程序,无论是简单的HTTP请求,还是复杂的HTTP交互,都能得心应手。通过深入了解和恰当配置,你可以充分利用这个库的优势,...
HttpClient 3.1需要依赖commons-httpclient-3.1.jar、commons-logging.jar和commons-codec.jar这些jar包,而HttpClient 4.x的最新版本为4.1.2,官方不再维护3.x版本。HttpClient 4.x的jar包可以在Apache官方网站上...
总结来说,HttpClient提供了一个强大而灵活的接口来处理HTTP请求,而忽略SSL验证的配置则允许我们在非生产环境中快速地进行测试和开发。但请记住,忽视SSL验证在生产环境中可能会导致安全隐患,务必谨慎对待。
总结起来,`httpclient4.3工具类`是一个针对HttpClient 4.3的自定义包装,它封装了常见的HTTP操作,提供了便捷的接口供项目中使用。理解这个工具类的内部实现和HttpClient的核心概念,将有助于更好地利用它进行HTTP...
总结来说,HttpClient的封装是为了提高代码的可维护性和易用性,通过隐藏复杂实现细节,提供简洁的API接口,使开发更加高效。了解封装原理和实现方式对于Java网络编程非常重要,尤其是在处理大量HTTP请求的项目中。
总结,HttpClient 4.5.3版本为开发者提供了强大而灵活的HTTP客户端工具,通过理解并熟练掌握其API和核心概念,我们可以更高效地进行HTTP通信,提升应用程序的质量和性能。对于Java开发者来说,HttpClient无疑是一个...
五、总结 HttpClient作为Java网络编程的重要工具,其强大的功能和灵活性使其在网络爬虫开发中扮演了不可或缺的角色。通过熟练掌握HttpClient的使用,开发者可以构建出稳定、高效的网络爬虫,实现对互联网数据的高效...
五、总结 HttpClient 4.1.2作为Java中的HTTP客户端库,以其强大的功能、良好的可扩展性和灵活性,为开发者提供了便捷的HTTP通信解决方案。尽管后续版本(如4.5.x)引入了更多改进,但HttpClient 4.1.2仍然在许多...
总结,HttpClient 4.5 是一款强大且灵活的 HTTP 客户端库,其源码结构清晰,设计模式巧妙,通过深入学习和实践,开发者可以更好地利用它来实现高效、安全的网络通信。理解 HttpClient 4.5 的源码,不仅有助于我们...
#### 六、总结 通过上述分析,我们可以看到使用 HttpClient 实现文件下载的过程相对简单,主要涉及到了 HTTP 请求的构造、执行以及响应数据的处理等步骤。此外,还需要注意异常处理及资源的释放,以确保程序的健壮...
总结来说,HttpClient 4.3 是一个专为 HTTP 通信设计的库,它提供了高效、易用的接口,用于构造和执行各种 HTTP 请求。开发者可以利用它来实现与 Web 服务的交互、爬虫、数据抓取等任务,而无需关心底层的网络细节。...
总结,HttpClient 3.1 JavaDoc CHM版为开发者提供了全面的API文档,帮助他们理解和使用HttpClient进行HTTP通信。虽然HttpClient已经更新到更高级的版本,但这个旧版本的文档对于维护旧项目或理解HTTP通信基础仍然...
总结来说,WPF中的异步调用Web API通过HttpClient能确保应用程序的响应性和用户体验。通过正确配置和使用HttpClient,开发者可以高效地与Web API进行通信,处理数据请求和响应,同时避免主线程被阻塞。记住,良好的...
五、总结 HttpClient库为Java开发者提供了一个功能强大的HTTP客户端工具,不仅支持基本的GET和POST操作,还提供了丰富的高级功能以应对复杂网络环境的需求。通过使用HttpClient,开发者可以更方便、安全地与HTTP...