HttpClient 是 Apache Jakarta Common 下的子项目,用来提供高效的、最新的、功能丰富的支持 HTTP 协议的客户端编程工具包,并且它支持 HTTP 协议最新的版本和建议。HttpClient 已经应用在很多的项目中,比如 Apache Jakarta 上很著名的另外两个开源项目 Cactus 和 HTMLUnit 都使用了 HttpClient。

HttpClient 提供的主要的功能,要知道更多详细的功能可以参见 HttpClient 的主页。

  • 实现了所有 HTTP 的方法(GET,POST,PUT,HEAD 等)
  • 支持自动转向
  • 支持 HTTPS 协议
  • 支持代理服务器等
import java.io.IOException;
import java.net.SocketTimeoutException;
import java.nio.charset.Charset;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.List;
import java.util.Map; import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLException;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager; import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.ParseException;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ConnectTimeoutException;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.conn.ssl.X509HostnameVerifier;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.params.CoreConnectionPNames;
import org.apache.http.protocol.HTTP;
import org.apache.http.util.EntityUtils; /**
* 封装了采用HttpClient发送HTTP请求的方法
* @see 本工具所采用的是HttpComponents-Client-4.2.1
* @see ===================================================================================================
* @see 开发HTTPS应用时,时常会遇到两种情况
* @see 1、测试服务器没有有效的SSL证书,客户端连接时就会抛异常
* @see javax.net.ssl.SSLPeerUnverifiedException: peer not authenticated
* @see 2、测试服务器有SSL证书,但可能由于各种不知名的原因,它还是会抛一堆烂码七糟的异常,诸如下面这两种
* @see javax.net.ssl.SSLException: hostname in certificate didn't match: <123.125.97.66> != <123.125.97.241>
* @see javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
* @see ===================================================================================================
* @see 这里使用的是HttpComponents-Client-4.2.1创建的连接,所以就要告诉它使用一个不同的TrustManager
* @see 由于SSL使用的模式是X.509,对于该模式,Java有一个特定的TrustManager,称为X509TrustManager
* @see TrustManager是一个用于检查给定的证书是否有效的类,所以我们自己创建一个X509TrustManager实例
* @see 而在X509TrustManager实例中,若证书无效,那么TrustManager在它的checkXXX()方法中将抛出CertificateException
* @see 既然我们要接受所有的证书,那么X509TrustManager里面的方法体中不抛出异常就行了
* @see 然后创建一个SSLContext并使用X509TrustManager实例来初始化之
* @see 接着通过SSLContext创建SSLSocketFactory,最后将SSLSocketFactory注册给HttpClient就可以了
* @see ===================================================================================================
* @version v1.7
* @history v1.0-->新建<code>sendGetRequest()</code>和<code>sendPostRequest()</code>方法
* @history v1.1-->新增<code>sendPostSSLRequest()</code>方法,用于发送HTTPS的POST请求
* @history v1.2-->新增<code>sendPostRequest()</code>方法,用于发送HTTP协议报文体为任意字符串的POST请求
* @history v1.3-->新增<code>java.net.HttpURLConnection</code>实现的<code>sendPostRequestByJava()</code>
* @history v1.4-->所有POST方法中增加连接超时限制和读取超时限制
* @history v1.5-->重组各方法,并补充自动获取HTTP响应文本编码的方式,移除<code>sendPostRequestByJava()</code>
* @history v1.6-->整理GET和POST请求方法,使之更为适用
* @history v1.7-->修正<code>sendPostRequest()</code>请求的CONTENT_TYPE头信息,并优化各方法参数及内部处理细节
* @create Feb 1, 2012 3:02:27 PM
* @update Jul 23, 2013 1:18:35 PM
* @author 玄玉<http://blog.csdn.net/jadyer>
*/
public class HttpClientUtil {
private HttpClientUtil(){} /**
* 发送HTTP_GET请求
* @see 1)该方法会自动关闭连接,释放资源
* @see 2)方法内设置了连接和读取超时时间,单位为毫秒,超时或发生其它异常时方法会自动返回"通信失败"字符串
* @see 3)请求参数含中文时,经测试可直接传入中文,HttpClient会自动编码发给Server,应用时应根据实际效果决定传入前是否转码
* @see 4)该方法会自动获取到响应消息头中[Content-Type:text/html; charset=GBK]的charset值作为响应报文的解码字符集
* @see 若响应消息头中无Content-Type属性,则会使用HttpClient内部默认的ISO-8859-1作为响应报文的解码字符集
* @param requestURL 请求地址(含参数)
* @return 远程主机响应正文
*/
public static String sendGetRequest(String reqURL){
String respContent = "通信失败"; //响应内容
HttpClient httpClient = new DefaultHttpClient(); //创建默认的httpClient实例
//设置代理服务器
//httpClient.getParams().setParameter(ConnRoutePNames.DEFAULT_PROXY, new HttpHost("10.0.0.4", 8080));
httpClient.getParams().setParameter(CoreConnectionPNames.CONNECTION_TIMEOUT, ); //连接超时10s
httpClient.getParams().setParameter(CoreConnectionPNames.SO_TIMEOUT, ); //读取超时20s
HttpGet httpGet = new HttpGet(reqURL); //创建org.apache.http.client.methods.HttpGet
try{
HttpResponse response = httpClient.execute(httpGet); //执行GET请求
HttpEntity entity = response.getEntity(); //获取响应实体
if(null != entity){
//respCharset=EntityUtils.getContentCharSet(entity)也可以获取响应编码,但从4.1.3开始不建议使用这种方式
Charset respCharset = ContentType.getOrDefault(entity).getCharset();
respContent = EntityUtils.toString(entity, respCharset);
//Consume response content
EntityUtils.consume(entity);
}
System.out.println("-------------------------------------------------------------------------------------------");
StringBuilder respHeaderDatas = new StringBuilder();
for(Header header : response.getAllHeaders()){
respHeaderDatas.append(header.toString()).append("\r\n");
}
String respStatusLine = response.getStatusLine().toString(); //HTTP应答状态行信息
String respHeaderMsg = respHeaderDatas.toString().trim(); //HTTP应答报文头信息
String respBodyMsg = respContent; //HTTP应答报文体信息
System.out.println("HTTP应答完整报文=[" + respStatusLine + "\r\n" + respHeaderMsg + "\r\n\r\n" + respBodyMsg + "]");
System.out.println("-------------------------------------------------------------------------------------------");
} catch (ConnectTimeoutException cte){
//Should catch ConnectTimeoutException, and don`t catch org.apache.http.conn.HttpHostConnectException
LogUtil.getLogger().error("请求通信[" + reqURL + "]时连接超时,堆栈轨迹如下", cte);
} catch (SocketTimeoutException ste){
LogUtil.getLogger().error("请求通信[" + reqURL + "]时读取超时,堆栈轨迹如下", ste);
}catch(ClientProtocolException cpe){
//该异常通常是协议错误导致:比如构造HttpGet对象时传入协议不对(将'http'写成'htp')or响应内容不符合HTTP协议要求等
LogUtil.getLogger().error("请求通信[" + reqURL + "]时协议异常,堆栈轨迹如下", cpe);
}catch(ParseException pe){
LogUtil.getLogger().error("请求通信[" + reqURL + "]时解析异常,堆栈轨迹如下", pe);
}catch(IOException ioe){
//该异常通常是网络原因引起的,如HTTP服务器未启动等
LogUtil.getLogger().error("请求通信[" + reqURL + "]时网络异常,堆栈轨迹如下", ioe);
}catch (Exception e){
LogUtil.getLogger().error("请求通信[" + reqURL + "]时偶遇异常,堆栈轨迹如下", e);
}finally{
//关闭连接,释放资源
httpClient.getConnectionManager().shutdown();
}
return respContent;
} /**
* 发送HTTP_POST请求
* @see 1)该方法允许自定义任何格式和内容的HTTP请求报文体
* @see 2)该方法会自动关闭连接,释放资源
* @see 3)方法内设置了连接和读取超时时间,单位为毫秒,超时或发生其它异常时方法会自动返回"通信失败"字符串
* @see 4)请求参数含中文等特殊字符时,可直接传入本方法,并指明其编码字符集encodeCharset参数,方法内部会自动对其转码
* @see 5)该方法在解码响应报文时所采用的编码,取自响应消息头中的[Content-Type:text/html; charset=GBK]的charset值
* @see 若响应消息头中未指定Content-Type属性,则会使用HttpClient内部默认的ISO-8859-1
* @param reqURL 请求地址
* @param reqData 请求参数,若有多个参数则应拼接为param11=value11&22=value22&33=value33的形式
* @param encodeCharset 编码字符集,编码请求数据时用之,此参数为必填项(不能为""或null)
* @return 远程主机响应正文
*/
public static String sendPostRequest(String reqURL, String reqData, String encodeCharset){
String reseContent = "通信失败";
HttpClient httpClient = new DefaultHttpClient();
httpClient.getParams().setParameter(CoreConnectionPNames.CONNECTION_TIMEOUT, );
httpClient.getParams().setParameter(CoreConnectionPNames.SO_TIMEOUT, );
HttpPost httpPost = new HttpPost(reqURL);
//由于下面使用的是new StringEntity(....),所以默认发出去的请求报文头中CONTENT_TYPE值为text/plain; charset=ISO-8859-1
//这就有可能会导致服务端接收不到POST过去的参数,比如运行在Tomcat6.0.36中的Servlet,所以我们手工指定CONTENT_TYPE头消息
httpPost.setHeader(HTTP.CONTENT_TYPE, "application/x-www-form-urlencoded; charset=" + encodeCharset);
try{
httpPost.setEntity(new StringEntity(reqData==null?"":reqData, encodeCharset));
HttpResponse response = httpClient.execute(httpPost);
HttpEntity entity = response.getEntity();
if (null != entity) {
reseContent = EntityUtils.toString(entity, ContentType.getOrDefault(entity).getCharset());
EntityUtils.consume(entity);
}
} catch (ConnectTimeoutException cte){
LogUtil.getLogger().error("请求通信[" + reqURL + "]时连接超时,堆栈轨迹如下", cte);
} catch (SocketTimeoutException ste){
LogUtil.getLogger().error("请求通信[" + reqURL + "]时读取超时,堆栈轨迹如下", ste);
}catch(Exception e){
LogUtil.getLogger().error("请求通信[" + reqURL + "]时偶遇异常,堆栈轨迹如下", e);
}finally{
httpClient.getConnectionManager().shutdown();
}
return reseContent;
} /**
* 发送HTTP_POST_SSL请求
* @see 1)该方法会自动关闭连接,释放资源
* @see 2)该方法亦可处理普通的HTTP_POST请求
* @see 3)当处理HTTP_POST_SSL请求时,默认请求的是对方443端口,除非reqURL参数中指明了SSL端口
* @see 4)方法内设置了连接和读取超时时间,单位为毫秒,超时或发生其它异常时方法会自动返回"通信失败"字符串
* @see 5)请求参数含中文等特殊字符时,可直接传入本方法,并指明其编码字符集encodeCharset参数,方法内部会自动对其转码
* @see 6)方法内部会自动注册443作为SSL端口,若实际使用中reqURL指定的SSL端口非443,可自行尝试更改方法内部注册的SSL端口
* @see 7)该方法在解码响应报文时所采用的编码,取自响应消息头中的[Content-Type:text/html; charset=GBK]的charset值
* @see 若响应消息头中未指定Content-Type属性,则会使用HttpClient内部默认的ISO-8859-1
* @param reqURL 请求地址
* @param params 请求参数
* @param encodeCharset 编码字符集,编码请求数据时用之,当其为null时,则取HttpClient内部默认的ISO-8859-1编码请求参数
* @return 远程主机响应正文
*/
public static String sendPostSSLRequest(String reqURL, Map<String, String> params, String encodeCharset){
String responseContent = "通信失败";
HttpClient httpClient = new DefaultHttpClient();
httpClient.getParams().setParameter(CoreConnectionPNames.CONNECTION_TIMEOUT, );
httpClient.getParams().setParameter(CoreConnectionPNames.SO_TIMEOUT, );
//创建TrustManager()
//用于解决javax.net.ssl.SSLPeerUnverifiedException: peer not authenticated
X509TrustManager trustManager = new X509TrustManager(){
@Override
public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {}
@Override
public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {}
@Override
public X509Certificate[] getAcceptedIssuers() {return null;}
};
//创建HostnameVerifier
//用于解决javax.net.ssl.SSLException: hostname in certificate didn't match: <123.125.97.66> != <123.125.97.241>
X509HostnameVerifier hostnameVerifier = new X509HostnameVerifier(){
@Override
public void verify(String host, SSLSocket ssl) throws IOException {}
@Override
public void verify(String host, X509Certificate cert) throws SSLException {}
@Override
public void verify(String host, String[] cns, String[] subjectAlts) throws SSLException {}
@Override
public boolean verify(String arg0, SSLSession arg1) {return true;}
};
try {
//TLS1.0与SSL3.0基本上没有太大的差别,可粗略理解为TLS是SSL的继承者,但它们使用的是相同的SSLContext
SSLContext sslContext = SSLContext.getInstance(SSLSocketFactory.TLS);
//使用TrustManager来初始化该上下文,TrustManager只是被SSL的Socket所使用
sslContext.init(null, new TrustManager[]{trustManager}, null);
//创建SSLSocketFactory
SSLSocketFactory socketFactory = new SSLSocketFactory(sslContext, hostnameVerifier);
//通过SchemeRegistry将SSLSocketFactory注册到HttpClient上
httpClient.getConnectionManager().getSchemeRegistry().register(new Scheme("https", , socketFactory));
//创建HttpPost
HttpPost httpPost = new HttpPost(reqURL);
//由于下面使用的是new UrlEncodedFormEntity(....),所以这里不需要手工指定CONTENT_TYPE为application/x-www-form-urlencoded
//因为在查看了HttpClient的源码后发现,UrlEncodedFormEntity所采用的默认CONTENT_TYPE就是application/x-www-form-urlencoded
//httpPost.setHeader(HTTP.CONTENT_TYPE, "application/x-www-form-urlencoded; charset=" + encodeCharset);
//构建POST请求的表单参数
if(null != params){
List<NameValuePair> formParams = new ArrayList<NameValuePair>();
for(Map.Entry<String,String> entry : params.entrySet()){
formParams.add(new BasicNameValuePair(entry.getKey(), entry.getValue()));
}
httpPost.setEntity(new UrlEncodedFormEntity(formParams, encodeCharset));
}
HttpResponse response = httpClient.execute(httpPost);
HttpEntity entity = response.getEntity();
if (null != entity) {
responseContent = EntityUtils.toString(entity, ContentType.getOrDefault(entity).getCharset());
EntityUtils.consume(entity);
}
} catch (ConnectTimeoutException cte){
LogUtil.getLogger().error("请求通信[" + reqURL + "]时连接超时,堆栈轨迹如下", cte);
} catch (SocketTimeoutException ste){
LogUtil.getLogger().error("请求通信[" + reqURL + "]时读取超时,堆栈轨迹如下", ste);
} catch (Exception e) {
LogUtil.getLogger().error("请求通信[" + reqURL + "]时偶遇异常,堆栈轨迹如下", e);
} finally {
httpClient.getConnectionManager().shutdown();
}
return responseContent;
}
}

下面是测试代码

public static void main(String[] args) {
Map<String, String> params = new HashMap<String, String>();
params.put("merNo", "");
params.put("signType", "MD5");
params.put("merBindAgrNo", "");
params.put("interfaceVersion", "1.0.0.0");
params.put("amount", "");
params.put("orderDate", "");
params.put("orderNo", "UDP1208230917531231111");
params.put("merReqTime", "");
params.put("goodsDesc", "为号码交费充值元");
params.put("goodsName", "中国联通交费充值");
params.put("userIdeMark", "");
params.put("bankAgrMode", "");
params.put("signMsg", "3ced24a118461043901d47815e6905a9");
System.out.println(HttpClientUtil.sendPostSSLRequest("https://123.125.97.66:8085/pay/servlet/CreditPayReqServlte", params, "UTF-8"));
}

HttpClient工具类的更多相关文章

  1. Java开发小技巧(五):HttpClient工具类

    前言 大多数Java应用程序都会通过HTTP协议来调用接口访问各种网络资源,JDK也提供了相应的HTTP工具包,但是使用起来不够方便灵活,所以我们可以利用Apache的HttpClient来封装一个具 ...

  2. 基于HttpClient4.5.2实现的HttpClient工具类

    1.maven依赖: <dependency> <groupId>org.apache.commons</groupId> <artifactId>co ...

  3. 转:轻松把玩HttpClient之封装HttpClient工具类(一)(现有网上分享中的最强大的工具类)

    搜了一下网络上别人封装的HttpClient,大部分特别简单,有一些看起来比较高级,但是用起来都不怎么好用.调用关系不清楚,结构有点混乱.所以也就萌生了自己封装HttpClient工具类的想法.要做就 ...

  4. 使用单例模式实现自己的HttpClient工具类

    引子 在Android开发中我们经常会用到网络连接功能与服务器进行数据的交互,为此Android的SDK提供了Apache的HttpClient 来方便我们使用各种Http服务.你可以把HttpCli ...

  5. Android开发实现HttpClient工具类

    在Android开发中我们经常会用到网络连接功能与服务器进行数据的交互,为此Android的SDK提供了Apache的HttpClient来方便我们使用各种Http服务.你可以把HttpClient想 ...

  6. httpclient工具类,post请求发送json字符串参数,中文乱码处理

    在使用httpclient发送post请求的时候,接收端中文乱码问题解决. 正文: 我们都知道,一般情况下使用post请求是不会出现中文乱码的.可是在使用httpclient发送post请求报文含中文 ...

  7. 通过Httpclient工具类,实现接口请求

    package luckyweb.seagull.util; import org.apache.http.NameValuePair; import org.apache.http.client.e ...

  8. Httpclient 工具类(get,put)

    package com.googosoft.until; import java.io.IOException; import org.apache.http.HttpEntity; import o ...

  9. 轻松把玩HttpClient之封装HttpClient工具类(五),携带Cookie的请求

    近期更新了一下HttpClientUtil工具类代码,主要是加入了一个參数HttpContext,这个是用来干嘛的呢?事实上是用来保存和传递Cookie所须要的. 由于我们有非常多时候都须要登录.然后 ...

  10. HttpClient工具类v1.7

    package com.cucpay.fundswap.util; import java.io.IOException; import java.net.SocketTimeoutException ...

随机推荐

  1. 完整的拆分nginx访问日志

    <pre name="code" class="html"> 10.168.255.134 [09/Oct/2016:15:28:52 +0800] ...

  2. 福建省队集训被虐记——DAY1

    今天算是省冬的第一天--早上柯黑出题,说是"信心欢乐赛",其实是"使你失去信心.不再欢乐的比赛" 顺便orz一下来看这篇文章的各路神犇--求轻虐 水题 (py. ...

  3. Quartus DSE 初步应用

    介绍 Design Space Explorer (DSE) is a program that automates the process of finding the optimal collec ...

  4. Inorder Successor in BST 解答

    Question Given a binary search tree and a node in it, find the in-order successor of that node in th ...

  5. Zigzag Iterator 解答

    Question Given two 1d vectors, implement an iterator to return their elements alternately. For examp ...

  6. Android学习总结——去除标题栏

    1.继承app.Activity的Activity去除标题栏 @Override protected void onCreate(Bundle savedInstanceState) { super. ...

  7. Linux 编译安装 apache 2.4

    在安装apache之前需要准备一些必要的依赖包 gcc安装: #yum install -y gcc gcc-c++安装: #yum install gcc-c++  apr安装: 下载包:apr-1 ...

  8. CSS彻底研究(3) - 浮动,定位

    Github pages 博文 CSS彻底研究(3)-浮动,定位 一 . 浮动float I . 定义及规则 float默认为none,对应标准流的情况.当float : left;时,元素就会向其父 ...

  9. Chrome 开发者工具详解(4):Profiles 面板

    概述 当前使用的Chrome最新版为54.0.2840.71,这个版本的Profiles面板比之前提供的功能更多也更强大,下面是该面板所包含的功能点: Record JavaScript CPU Pr ...

  10. Jquery on() 动态绑定事件

    之前就一直受这个问题的困扰,在jQuery1.7版本之后添加了on方法,之前就了解过,其优越性高于live(),bind(),delegate()等方法,在此之前项目中想用这个来测试结果发现,居然动态 ...