package com.cucpay.fundswap.util;

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, 10000); //连接超时10s
httpClient.getParams().setParameter(CoreConnectionPNames.SO_TIMEOUT, 20000); //读取超时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, 10000);
httpClient.getParams().setParameter(CoreConnectionPNames.SO_TIMEOUT, 20000);
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, 10000);
httpClient.getParams().setParameter(CoreConnectionPNames.SO_TIMEOUT, 20000);
//创建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", 443, 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", "301100100001630");
params.put("signType", "MD5");
params.put("merBindAgrNo", "00003018007000006450000013866742");
params.put("interfaceVersion", "1.0.0.0");
params.put("amount", "1000");
params.put("orderDate", "20120823");
params.put("orderNo", "UDP1208230917531231111");
params.put("merReqTime", "20120823091802");
params.put("goodsDesc", "为号码交费充值元");
params.put("goodsName", "中国联通交费充值");
params.put("userIdeMark", "3");
params.put("bankAgrMode", "9");
params.put("signMsg", "3ced24a118461043901d47815e6905a9");
System.out.println(HttpClientUtil.sendPostSSLRequest("https://123.125.97.66:8085/pay/servlet/CreditPayReqServlte", params, "UTF-8"));
}

HttpClient工具类v1.7的更多相关文章

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

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

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

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

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

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

  4. Mina工具类v1.5

    package com.cucpay.fundswap.util; import java.net.InetSocketAddress; import java.nio.charset.Charset ...

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

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

  6. ZXing工具类v1.0

    package com.jadyer.util; import java.awt.Graphics2D; import java.awt.image.BufferedImage; import jav ...

  7. Android开发实现HttpClient工具类

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

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

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

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

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

随机推荐

  1. exFAT是支持Mac和Win的

    exFAT是支持Mac和Win的 转自: http://bbs.feng.com/read-htm-tid-8214017.html

  2. webservice 协议

    Web   Service使用的是   SOAP   (Simple   Object   Access   Protocol)协议soap协议只是用来封装消息用的.封装后的消息你可以通过各种已有的协 ...

  3. 对Excel文件的操作

    ①.将文件设为“嵌入的资源”,Template修改不灵活:Stream stream=this.GetType().Assembly.GetManifestResourceStream(Templat ...

  4. 28. 字符串的全排列之第2篇[string permutation with repeating chars]

    [本文链接] http://www.cnblogs.com/hellogiser/p/string-permutation-with-repeating-chars.html [题目] 输入一个字符串 ...

  5. Android开发数据库三层应用-DataSnap

    Android开发数据库三层应用-DataSnap http://www.2ccc.com/news/Html/?1517.html 核心提示:我觉得Delphi最强大的的功能之一就是开发数据库三层应 ...

  6. 【JAVA、C++】LeetCode 003 Longest Substring Without Repeating Characters

    Given a string, find the length of the longest substring without repeating characters. For example, ...

  7. August 6th, 2016, Week 32nd, Saturday

    It is not the mountain we conquer, but ourselvess. 我们征服的不是高山,而是我们自己. Difficulties and obstacles, jus ...

  8. Linux C 单链表 读取文件 并排序 实例并解释

    C的指针挺头疼的,先看一个例子: 给指针赋值和通过指针进行赋值这两种操作的差别确实让人费解.谨记区分的重要方法是:如果对左操作数进行解引用,则修改的是指针所指对象的值:    如果没有使用解引用操作, ...

  9. mysql 建表语句

    修改id为自动增长: alter table book b_ISBN int(11) auto_increment;   自动增长要加的:auto_increment 基本的sql语句: 选择:sel ...

  10. mongoDb学习以及spring管理

    1.windows下的安装http://www.cnblogs.com/liuzhiying/p/5915741.html 2.慕课网学习单机操作mongoDb 赋权限:http://blog.csd ...