HttpClient工具类v1.6

  1 package com.cucpay.tradeportal.util;
  2 
  3 import java.io.IOException;
  4 import java.net.SocketTimeoutException;
  5 import java.nio.charset.Charset;
  6 import java.security.cert.CertificateException;
  7 import java.security.cert.X509Certificate;
  8 import java.util.ArrayList;
  9 import java.util.List;
 10 import java.util.Map;
 11 
 12 import javax.net.ssl.SSLContext;
 13 import javax.net.ssl.SSLException;
 14 import javax.net.ssl.SSLSession;
 15 import javax.net.ssl.SSLSocket;
 16 import javax.net.ssl.TrustManager;
 17 import javax.net.ssl.X509TrustManager;
 18 
 19 import org.apache.http.HttpEntity;
 20 import org.apache.http.HttpResponse;
 21 import org.apache.http.NameValuePair;
 22 import org.apache.http.ParseException;
 23 import org.apache.http.client.ClientProtocolException;
 24 import org.apache.http.client.HttpClient;
 25 import org.apache.http.client.entity.UrlEncodedFormEntity;
 26 import org.apache.http.client.methods.HttpGet;
 27 import org.apache.http.client.methods.HttpPost;
 28 import org.apache.http.client.utils.URLEncodedUtils;
 29 import org.apache.http.conn.ConnectTimeoutException;
 30 import org.apache.http.conn.scheme.Scheme;
 31 import org.apache.http.conn.ssl.SSLSocketFactory;
 32 import org.apache.http.conn.ssl.X509HostnameVerifier;
 33 import org.apache.http.entity.ContentType;
 34 import org.apache.http.entity.StringEntity;
 35 import org.apache.http.impl.client.DefaultHttpClient;
 36 import org.apache.http.message.BasicNameValuePair;
 37 import org.apache.http.params.CoreConnectionPNames;
 38 import org.apache.http.util.EntityUtils;
 39 
 40 /**
 41  * 封装了采用HttpClient发送HTTP请求的方法
 42  * @see 本工具所采用的是最新的HttpComponents-Client-4.2.1
 43  * @see ===================================================================================================
 44  * @see 开发HTTPS应用时,时常会遇到两种情况
 45  * @see 1、测试服务器没有有效的SSL证书,客户端连接时就会抛异常
 46  * @see    javax.net.ssl.SSLPeerUnverifiedException: peer not authenticated
 47  * @see 2、测试服务器有SSL证书,但可能由于各种不知名的原因,它还是会抛一堆烂码七糟的异常,诸如下面这几种
 48  * @see    javax.net.ssl.SSLException: hostname in certificate didn't match: <123.125.97.66> != <123.125.97.241>
 49  * @see    javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed:
 50  * @see    sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
 51  * @see ===================================================================================================
 52  * @see 这里使用的是HttpComponents-Client-4.1.2创建的连接,所以就要告诉它使用一个不同的TrustManager
 53  * @see 由于SSL使用的模式是X.509,对于该模式,Java有一个特定的TrustManager,称为X509TrustManager
 54  * @see TrustManager是一个用于检查给定的证书是否有效的类,所以我们自己创建一个X509TrustManager实例
 55  * @see 而在X509TrustManager实例中,若证书无效,那么TrustManager在它的checkXXX()方法中将抛出CertificateException
 56  * @see 既然我们要接受所有的证书,那么X509TrustManager里面的方法体中不抛出异常就行了
 57  * @see 然后创建一个SSLContext并使用X509TrustManager实例来初始化之
 58  * @see 接着通过SSLContext创建SSLSocketFactory,最后将SSLSocketFactory注册给HttpClient就可以了
 59  * @see ===================================================================================================
 60  * @version v1.6
 61  * @history v1.0-->新建<code>sendGetRequest()</code>和<code>sendPostRequest()</code>方法
 62  * @history v1.1-->新增<code>sendPostSSLRequest()</code>方法,用于发送HTTPS的POST请求
 63  * @history v1.2-->新增<code>sendPostRequest()</code>方法,用于发送HTTP协议报文体为任意字符串的POST请求
 64  * @history v1.3-->新增<code>java.net.HttpURLConnection</code>实现的<code>sendPostRequestByJava()</code>
 65  * @history v1.4-->所有POST方法中增加连接超时限制和读取超时限制
 66  * @history v1.5-->重组各方法,并补充自动获取HTTP响应文本编码的方式,移除<code>sendPostRequestByJava()</code>
 67  * @history v1.6-->整理GET和POST请求方法,使之更为适用
 68  * @create Feb 1, 2012 3:02:27 PM
 69  * @update Apr 15, 2013 10:44:35 AM
 70  */
 71 public class HttpClientUtil {
 72     private HttpClientUtil(){}
 73     
 74     /**
 75      * 发送HTTP_GET请求
 76      * @see 1)该方法会自动关闭连接,释放资源
 77      * @see 2)该方法会自动获取到响应消息头中[Content-Type:text/html; charset=GBK]的charset值作为响应报文解码字符集
 78      * @see   若响应消息头中无Content-Type属性,则默认使用HttpClient内部默认的ISO-8859-1
 79      * @param requestURL 请求地址(含参数)
 80      * @return 远程主机响应正文
 81      */
 82     public static String sendGetRequest(String reqURL){
 83         long respLen = 0;           //响应长度
 84         String respContent = null;  //响应内容
 85         Charset respCharset = null; //响应编码
 86         HttpClient httpClient = new DefaultHttpClient(); //创建默认的httpClient实例
 87         HttpGet httpGet = new HttpGet(reqURL);           //创建org.apache.http.client.methods.HttpGet
 88         try{
 89             HttpResponse response = httpClient.execute(httpGet); //执行GET请求
 90             HttpEntity entity = response.getEntity();            //获取响应实体
 91             if(null != entity){
 92                 //使用EntityUtils.getContentCharSet(entity)也可以获取响应编码,但从4.1.3开始不建议使用这种方式
 93                 respCharset = ContentType.getOrDefault(entity).getCharset();
 94                 respLen = entity.getContentLength();
 95                 respContent = EntityUtils.toString(entity, respCharset);
 96                 //Consume response content
 97                 EntityUtils.consume(entity);
 98             }
 99             System.out.println("-----------------------------------------------------------------------");
100             System.out.println("请求地址: " + httpGet.getURI());
101             System.out.println("响应状态: " + response.getStatusLine());
102             System.out.println("响应长度: " + respLen);
103             System.out.println("响应编码: " + respCharset);
104             System.out.println("响应内容: " + respContent);
105             System.out.println("-----------------------------------------------------------------------");
106         }catch(ClientProtocolException e){
107             //该异常通常是协议错误导致:比如构造HttpGet对象时传入协议不对(将'http'写成'htp')or响应内容不符合HTTP协议要求等
108             LogUtil.getLogger().error("协议异常,堆栈信息如下", e);
109         }catch(ParseException e){
110             LogUtil.getLogger().error(e.getMessage(), e);
111         }catch(IOException e){
112             //该异常通常是网络原因引起的,如HTTP服务器未启动等
113             LogUtil.getLogger().error("网络异常,堆栈信息如下", e);
114         }finally{
115             //关闭连接,释放资源
116             httpClient.getConnectionManager().shutdown();
117         }
118         return respContent;
119     }
120     
121     
122     /**
123      * 发送HTTP_POST请求
124      * @see 1)该方法的优点在于-->允许自定义任何格式和内容的HTTP请求报文体,只要你熟悉HTTP/1.1协议
125      * @see 2)该方法会自动关闭连接,释放资源
126      * @see 3)方法内设置了连接和读取超时时间,单位为毫秒,超时后方法会自动返回空字符串
127      * @see 4)请求参数含中文等特殊字符时,可在传入前自行<code>URLEncoder.encode(string,encodeCharset)</code>,再指定encodeCharset为null
128      * @see 5)亦可指定encodeCharset参数值,由本方法代为编码
129      * @see 6)该方法在解码响应报文时所采用的编码,为响应消息头中[Content-Type:text/html; charset=GBK]的charset值
130      * @see   若响应消息头中未指定Content-Type属性,则默认使用HttpClient内部默认的ISO-8859-1
131      * @param reqURL        请求地址
132      * @param reqData       请求参数,若有多个参数则应拼接为param11=value11&22=value22&33=value33的形式
133      * @param encodeCharset 编码字符集,编码请求数据时用之,其为null表示请求参数已编码完毕,不需要二次编码
134      * @return 远程主机响应正文
135      */
136     public static String sendPostRequest(String reqURL, String reqData, String encodeCharset){
137         String reseContent = "";
138         HttpClient httpClient = new DefaultHttpClient();
139         httpClient.getParams().setParameter(CoreConnectionPNames.CONNECTION_TIMEOUT, 1000);
140         httpClient.getParams().setParameter(CoreConnectionPNames.SO_TIMEOUT, 2000);
141         HttpPost httpPost = new HttpPost(reqURL);
142         try{
143             if(null != reqData){
144                 if(reqData.contains("&")){
145                     List<NameValuePair> formParams = new ArrayList<NameValuePair>();
146                     for(String str : reqData.split("&")){
147                         formParams.add(new BasicNameValuePair(str.substring(0,str.indexOf("=")), str.substring(str.indexOf("=")+1)));
148                     }
149                     httpPost.setEntity(new StringEntity(URLEncodedUtils.format(formParams, encodeCharset)));
150                 }else{
151                     httpPost.setEntity(new StringEntity(reqData, encodeCharset));
152                 }
153             }
154             HttpResponse response = httpClient.execute(httpPost);
155             HttpEntity entity = response.getEntity();
156             if (null != entity) {
157                 reseContent = EntityUtils.toString(entity, ContentType.getOrDefault(entity).getCharset());
158                 EntityUtils.consume(entity);
159             }
160         } catch (ConnectTimeoutException cte){
161             LogUtil.getLogger().error("与[" + reqURL + "]连接超时,自动返回空字符串");
162         } catch (SocketTimeoutException ste){
163             LogUtil.getLogger().error("与[" + reqURL + "]读取超时,自动返回空字符串");
164         }catch(Exception e){
165             LogUtil.getLogger().error("与[" + reqURL + "]通信异常,堆栈信息如下", e);
166         }finally{
167             httpClient.getConnectionManager().shutdown();
168         }
169         return reseContent;
170     }
171     
172     
173     /**
174      * 发送HTTP_POST_SSL请求
175      * @see 1)该方法会自动关闭连接,释放资源
176      * @see 2)该方法亦可处理普通的HTTP_POST请求
177      * @see 3)方法内设置了连接和读取超时时间,单位为毫秒,超时后方法会自动返回空字符串
178      * @see 4)请求参数含中文等特殊字符时,可在传入前自行<code>URLEncoder.encode(string,encodeCharset)</code>,再指定encodeCharset为null
179      * @see 5)亦可指定encodeCharset参数值,由本方法代为编码
180      * @see 6)该方法在解码响应报文时所采用的编码,为响应消息头中[Content-Type:text/html; charset=GBK]的charset值
181      * @see   若响应消息头中未指定Content-Type属性,则默认使用HttpClient内部默认的ISO-8859-1
182      * @see 7)若reqURL的HTTPS端口不是默认的443,那么只需要在reqURL中指明其实际的HTTPS端口即可,而无需修改本方法内部指定的443
183      * @see   此时,方法默认会取指明的HTTPS端口进行连接..如reqURL=https://123.125.97.66:8085/pay/则实际请求即对方HTTPS_8085端口
184      * @param reqURL        请求地址
185      * @param params        请求参数
186      * @param encodeCharset 编码字符集,编码请求数据时用之,其为null表示请求参数已编码完毕,不需要二次编码
187      * @return 远程主机响应正文
188      */
189     public static String sendPostSSLRequest(String reqURL, Map<String, String> params, String encodeCharset){
190         String responseContent = "";
191         HttpClient httpClient = new DefaultHttpClient();
192         //设置代理服务器
193         //httpClient.getParams().setParameter(ConnRoutePNames.DEFAULT_PROXY, new HttpHost("10.0.0.4", 8080));
194         httpClient.getParams().setParameter(CoreConnectionPNames.CONNECTION_TIMEOUT, 1000);
195         httpClient.getParams().setParameter(CoreConnectionPNames.SO_TIMEOUT, 2000);
196         //创建TrustManager
197         //用于解决javax.net.ssl.SSLPeerUnverifiedException: peer not authenticated
198         X509TrustManager trustManager = new X509TrustManager(){
199             @Override
200             public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {}
201             @Override
202             public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {}
203             @Override
204             public X509Certificate[] getAcceptedIssuers() {return null;}
205         };
206         //创建HostnameVerifier
207         //用于解决javax.net.ssl.SSLException: hostname in certificate didn't match: <123.125.97.66> != <123.125.97.241>
208         X509HostnameVerifier hostnameVerifier = new X509HostnameVerifier(){
209             @Override
210             public void verify(String host, SSLSocket ssl) throws IOException {}
211             @Override
212             public void verify(String host, X509Certificate cert) throws SSLException {}
213             @Override
214             public void verify(String host, String[] cns, String[] subjectAlts) throws SSLException {}
215             @Override
216             public boolean verify(String arg0, SSLSession arg1) {return true;}
217         };
218         try {
219             //TLS1.0与SSL3.0基本上没有太大的差别,可粗略理解为TLS是SSL的继承者,但它们使用的是相同的SSLContext
220             SSLContext sslContext = SSLContext.getInstance(SSLSocketFactory.TLS);
221             //使用TrustManager来初始化该上下文,TrustManager只是被SSL的Socket所使用
222             sslContext.init(null, new TrustManager[]{trustManager}, null);
223             //创建SSLSocketFactory
224             SSLSocketFactory socketFactory = new SSLSocketFactory(sslContext, hostnameVerifier);
225             //通过SchemeRegistry将SSLSocketFactory注册到HttpClient上
226             httpClient.getConnectionManager().getSchemeRegistry().register(new Scheme("https", 443, socketFactory));
227             //创建HttpPost
228             HttpPost httpPost = new HttpPost(reqURL);
229             //httpPost.setHeader(HTTP.CONTENT_TYPE, "application/x-www-form-urlencoded; charset=UTF-8");
230             //构建POST请求的表单参数
231             if(null != params){
232                 List<NameValuePair> formParams = new ArrayList<NameValuePair>();
233                 for(Map.Entry<String,String> entry : params.entrySet()){
234                     formParams.add(new BasicNameValuePair(entry.getKey(), entry.getValue()));
235                 }
236                 httpPost.setEntity(new UrlEncodedFormEntity(formParams, encodeCharset));
237             }
238             HttpResponse response = httpClient.execute(httpPost);
239             HttpEntity entity = response.getEntity();
240             if (null != entity) {
241 //                //打印HTTP响应报文的第一行,即状态行
242 //                System.out.println(response.getStatusLine());
243 //                //打印HTTP响应头信息
244 //                for(Header header : response.getAllHeaders()){
245 //                    System.out.println(header.toString());
246 //                }
247                 responseContent = EntityUtils.toString(entity, ContentType.getOrDefault(entity).getCharset());
248                 EntityUtils.consume(entity);
249             }
250         } catch (ConnectTimeoutException cte){
251             //Should catch ConnectTimeoutException, and don`t catch org.apache.http.conn.HttpHostConnectException
252             LogUtil.getLogger().error("与[" + reqURL + "]连接超时,自动返回空字符串");
253         } catch (SocketTimeoutException ste){
254             LogUtil.getLogger().error("与[" + reqURL + "]读取超时,自动返回空字符串");
255         } catch (Exception e) {
256             LogUtil.getLogger().error("与[" + reqURL + "]通信异常,堆栈信息为", e);
257         } finally {
258             httpClient.getConnectionManager().shutdown();
259         }
260         return responseContent;
261     }
262 }

 

转载于:https://www.cnblogs.com/duer/archive/2013/04/16/3023349.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值