HttpClient在java中的使用

来源:互联网 发布:网络爱国事例 编辑:程序博客网 时间:2024/06/05 00:09


注:对下述文档的代码部分做了更新2016.03.03

项目中一直在使用HttpClient,版本是3.6的,负责维护的同事离职后,就没有更新过,在这次项目改版中决定对这块进行升级到4.3版本,查阅了一些资料写了部分出来,还不是很完善,后期有时间在更新

这里对httpclient如何获取原页面编码进行了一些处理,感觉还不是很完善,后期想到在处理吧

具体的理论东西就不说了,代码中注释都有一些说明。

直接上代码

[java] view plain copy
  1. /** 
  2.   * 项目名:NewsCrawlerV3.1 
  3.   * 文件名:InfoLoad.java 
  4.   * 作者:zhouyh 
  5.   * 时间:2015-10-14 上午08:46:47 
  6.   * 描述:TODO(用一句话描述该文件做什么)  
  7.   */  
  8. package com.boryou.module.load;  
  9.   
  10. import java.io.IOException;  
  11. import java.io.InputStream;  
  12. import java.io.InterruptedIOException;  
  13. import java.net.MalformedURLException;  
  14. import java.net.URI;  
  15. import java.net.URISyntaxException;  
  16. import java.net.URL;  
  17. import java.net.UnknownHostException;  
  18. import java.nio.charset.Charset;  
  19. import java.security.KeyManagementException;  
  20. import java.security.KeyStoreException;  
  21. import java.security.NoSuchAlgorithmException;  
  22. import java.security.cert.CertificateException;  
  23. import java.security.cert.X509Certificate;  
  24. import java.util.Random;  
  25. import java.util.regex.Matcher;  
  26. import java.util.regex.Pattern;  
  27. import java.util.zip.GZIPInputStream;  
  28.   
  29. import javax.net.ssl.SSLContext;  
  30. import javax.net.ssl.SSLException;  
  31.   
  32. import org.apache.http.Header;  
  33. import org.apache.http.HeaderElement;  
  34. import org.apache.http.HttpEntity;  
  35. import org.apache.http.HttpEntityEnclosingRequest;  
  36. import org.apache.http.HttpHost;  
  37. import org.apache.http.HttpRequest;  
  38. import org.apache.http.client.ClientProtocolException;  
  39. import org.apache.http.client.HttpRequestRetryHandler;  
  40. import org.apache.http.client.config.CookieSpecs;  
  41. import org.apache.http.client.config.RequestConfig;  
  42. import org.apache.http.client.methods.CloseableHttpResponse;  
  43. import org.apache.http.client.methods.HttpGet;  
  44. import org.apache.http.client.protocol.HttpClientContext;  
  45. import org.apache.http.conn.ConnectTimeoutException;  
  46. import org.apache.http.conn.ssl.SSLConnectionSocketFactory;  
  47. import org.apache.http.entity.ContentType;  
  48. import org.apache.http.impl.client.CloseableHttpClient;  
  49. import org.apache.http.impl.client.HttpClients;  
  50. import org.apache.http.impl.client.LaxRedirectStrategy;  
  51. import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;  
  52. import org.apache.http.protocol.HttpContext;  
  53. import org.apache.http.ssl.SSLContextBuilder;  
  54. import org.apache.http.ssl.TrustStrategy;  
  55. import org.apache.http.util.ByteArrayBuffer;  
  56.   
  57. import com.boryou.constant.Constant;  
  58. import com.boryou.util.Common;  
  59.   
  60.   
  61. /** 
  62.  * 类名: InfoLoad 
  63.  * 包名: com.boryou.module.load 
  64.  * 作者: zhouyh 
  65.  * 时间: 2015-10-14 上午08:46:47 
  66.  * 描述: 下载基础类,共监控、下载等模块使用  
  67.  */  
  68. public class InfoLoad {  
  69.     // 创建httpclient连接池  
  70.     private PoolingHttpClientConnectionManager httpClientConnectionManager = null;  
  71.       
  72.     /******单例模式声明开始******/  
  73.     //类初始化时,自动实例化,饿汉单例模式  
  74.     private static final InfoLoad infoLoad = new InfoLoad();  
  75.     /** 
  76.      *  
  77.      * 方法名:getInfoLoadInstance 
  78.      * 作者:zhouyh 
  79.      * 创建时间:2015-10-14 上午08:59:54 
  80.      * 描述:单例的静态方法,返回InfoLoad的实例 
  81.      * @return 
  82.      */  
  83.     public static InfoLoad getInfoLoadInstance(){  
  84.         return infoLoad;  
  85.     }  
  86.     /******单例模式声明结束******/  
  87.     /** 
  88.      * 私有的构造函数 
  89.      */  
  90.     private InfoLoad(){  
  91.         //初始化httpClient  
  92.         initHttpClient();  
  93.     }  
  94.     /** 
  95.      *  
  96.      * 方法名:initHttpClient 
  97.      * 作者:zhouyh 
  98.      * 创建时间:2015-10-14 上午11:00:30 
  99.      * 描述:创建httpclient连接池,并初始化httpclient 
  100.      */  
  101.     public void initHttpClient(){  
  102.         //创建httpclient连接池  
  103.         httpClientConnectionManager = new PoolingHttpClientConnectionManager();  
  104.         //设置连接池最大数量  
  105.         httpClientConnectionManager.setMaxTotal(Constant.HTTPCLIENT_CONNECTION_COUNT);  
  106.         //设置单个路由最大连接数量  
  107.         httpClientConnectionManager.setDefaultMaxPerRoute(Constant.HTTPCLIENT_MAXPERROUTE_COUNT);  
  108.     }  
  109.     //请求重试机制  
  110.     HttpRequestRetryHandler myRetryHandler = new HttpRequestRetryHandler() {  
  111.         public boolean retryRequest(IOException exception, int executionCount, HttpContext context) {  
  112.             if (executionCount >= 3) {  
  113.                 // 超过三次则不再重试请求  
  114.                 return false;  
  115.             }  
  116.             if (exception instanceof InterruptedIOException) {  
  117.                 // Timeout  
  118.                 return false;  
  119.             }  
  120.             if (exception instanceof UnknownHostException) {  
  121.                 // Unknown host  
  122.                 return false;  
  123.             }  
  124.             if (exception instanceof ConnectTimeoutException) {  
  125.                 // Connection refused  
  126.                 return false;             
  127.             }  
  128.             if (exception instanceof SSLException) {  
  129.                 // SSL handshake exception  
  130.                 return false;  
  131.             }  
  132.             HttpClientContext clientContext = HttpClientContext.adapt(context);  
  133.             HttpRequest request = clientContext.getRequest();  
  134.             boolean idempotent = !(request instanceof HttpEntityEnclosingRequest);  
  135.             if (idempotent) {  
  136.                 // Retry if the request is considered idempotent  
  137.                 return true;  
  138.             }  
  139.             return false;  
  140.         }  
  141.     };  
  142.     /** 
  143.      *  
  144.      * 方法名:getHttpClient 
  145.      * 作者:zhouyh 
  146.      * 创建时间:2016-2-18 下午01:23:32 
  147.      * 描述:多线程调用时,需要创建自己的httpclient 
  148.      * @return 
  149.      */  
  150.     public CloseableHttpClient getHttpClient(){       
  151.         // 创建全局的requestConfig  
  152.         RequestConfig requestConfig = RequestConfig.custom()  
  153.                 .setConnectTimeout(Constant.HTTPCLIENT_CONNECT_TIMEOUT)  
  154.                 .setSocketTimeout(Constant.HTTPCLIENT_SOCKET_TIMEOUT)  
  155.                 .setCookieSpec(CookieSpecs.BEST_MATCH).build();  
  156.         // 声明重定向策略对象  
  157.         LaxRedirectStrategy redirectStrategy = new LaxRedirectStrategy();  
  158.           
  159.         CloseableHttpClient httpClient = HttpClients.custom().setConnectionManager(httpClientConnectionManager)  
  160.                                                     .setDefaultRequestConfig(requestConfig)  
  161.                                                     .setRedirectStrategy(redirectStrategy)  
  162.                                                     .setRetryHandler(myRetryHandler)  
  163.                                                     .build();     
  164.         return httpClient;   
  165.     }  
  166.       
  167.     /** 
  168.      *  
  169.      * 方法名:loadForString 
  170.      * 作者:zhouyh 
  171.      * 创建时间:2015-10-14 下午02:22:19 
  172.      * 描述:根据传入的url获取下载信息 
  173.      * @param url 
  174.      * @param type 
  175.      * @return 
  176.      */  
  177.     public static String loadForString(String urlString, int type){  
  178.         String src = "";  
  179.         if(null==urlString || urlString.isEmpty() || !urlString.startsWith("http")){//如果urlString为null或者urlString为空,或urlString非http开头,返回src空值  
  180.             return src;  
  181.         }  
  182.         //创建response  
  183.         CloseableHttpResponse response = null;  
  184.         HttpGet httpGet = null;  
  185.         urlString = urlString.trim();//防止传入的urlString首尾有空格  
  186.         //转化String url为URI,解决url中包含特殊字符的情况  
  187.         try {  
  188.             URL url = new URL(urlString);  
  189.             URI uri = new URI(url.getProtocol(), url.getHost(), url.getPath(), url.getQuery(), null);  
  190.             httpGet = new HttpGet(uri);  
  191.             //针对https采用SSL的方式创建httpclient  
  192. //          if(urlString.startsWith("https")){  
  193. //              httpClient = createSSLClientDefault();  
  194. //              System.setProperty ("jsse.enableSNIExtension", "false");  
  195. //          }  
  196.             //设置请求头  
  197.             httpGet.addHeader("Accept","*/*");  
  198. //          httpGet.addHeader("Content-Type","application/x-www-form-urlencoded; charset=UTF-8");  
  199.             httpGet.addHeader("Connection","keep-alive");  
  200.             httpGet.addHeader("Accept-Encoding""gzip, deflate");  
  201.               
  202.             //设置USER_AGENT  
  203.             Random random = new Random();  
  204.             int randomInt = random.nextInt(4);  
  205.             System.err.println(randomInt);  
  206.               
  207.             httpGet.addHeader("User-Agent", Constant.USER_AGENT[randomInt]);  
  208.             //此处的代理暂时注释  
  209. //          String[] proxys = Constant.HTTPCLIENT_PROXY[randomInt].split("\\s+");  
  210. //          //添加代理  
  211. //          HttpHost proxy = new HttpHost(proxys[0].trim(), Integer.parseInt(proxys[1].trim()), "http");  
  212. //          RequestConfig config = RequestConfig.custom().setProxy(proxy).build();  
  213. //          httpGet.setConfig(config);    
  214.             //执行请求        
  215.             try {  
  216.                 if(urlString.startsWith("https")){  
  217.                     System.setProperty ("jsse.enableSNIExtension""false");  
  218.                     response = createSSLClientDefault().execute(httpGet);  
  219.                 }else{  
  220.                     response = infoLoad.getHttpClient().execute(httpGet);  
  221.                 }  
  222.             } catch (Exception e) {  
  223.                 e.printStackTrace();  
  224.             }  
  225.               
  226.             //得到响应状态码  
  227.             int statuCode = response.getStatusLine().getStatusCode();  
  228.             //根据状态码进行逻辑处理  
  229.             switch (statuCode){  
  230.             case 200:  
  231.                 //获得响应实体  
  232.                 HttpEntity entity = response.getEntity();  
  233.                 /**  
  234.                  * 仿浏览器获取网页编码  
  235.                  * 浏览器是先从content-type的charset(响应头信息)中获取编码,  
  236.                  * 如果获取不了,则会从meta(HTML里的代码)中获取charset的编码值  
  237.                  */  
  238.                 //第一步-->处理网页字符编码  
  239.                 String charset = null;  
  240.                 ContentType contentType = null;  
  241.                 contentType = ContentType.getOrDefault(entity);  
  242.                 Charset charsets = contentType.getCharset();  
  243.                 if(null != charsets){  
  244.                     charset = charsets.toString();  
  245.                 }  
  246.                 //判断返回的数据流是否采用了gzip压缩  
  247.                 Header header = entity.getContentEncoding();  
  248.                 boolean isGzip = false;  
  249.                 if(null != header){  
  250.                     for(HeaderElement headerElement : header.getElements()){  
  251.                         if(headerElement.getName().equalsIgnoreCase("gzip")){  
  252.                             isGzip = true;  
  253.                         }  
  254.                     }  
  255.                 }  
  256.                 //获得响应流  
  257.                 InputStream inputStream = entity.getContent();  
  258.                 ByteArrayBuffer buffer = new ByteArrayBuffer(4096);  
  259.                 byte[] tmp = new byte[4096];  
  260.                 int count;  
  261.                 if(isGzip){//如果采用了Gzip压缩,则进行gizp压缩处理  
  262.                     GZIPInputStream gzipInputStream = new GZIPInputStream(inputStream);  
  263.                     while((count=gzipInputStream.read(tmp)) != -1){  
  264.                         buffer.append(tmp, 0, count);  
  265.                     }  
  266.                 }else{//处理非gzip格式的数据  
  267.                     while((count=inputStream.read(tmp)) != -1){  
  268.                         buffer.append(tmp, 0, count);  
  269.                     }  
  270.                 }  
  271.                 //第二步--->如果第一步contenttyp未获取到编码,这里从meta标签中获取  
  272.                 if(null==charset || "".equals(charset) || "null".equals(charset)   
  273.                         || "zh-cn".equalsIgnoreCase(charset)){  
  274.                     charset = getCharsetFromMetaTag(buffer, urlString);  
  275.                 }  
  276.                 //根据获取的字符编码转为string类型  
  277.                 src = new String(buffer.toByteArray(), charset);  
  278.                 //替换特殊编码  
  279.                 src = replaceStr(src);  
  280.                 //转化Unicode编码格式]  
  281.                 src = Common.decodeUnicode(src);  
  282. //              System.out.println(src);  
  283.                 break;  
  284.             case 400:  
  285.                 System.out.println("下载400错误代码,请求出现语法错误" + urlString);  
  286.                 //TODO 要进行判断是列表页还是正文页下载,再去修改数据库,下同  
  287.                 //TODO 此处添加对mongodb数据库的操作,将该url的isStart改为0,暂时不在进行监控,后续根据模板状态为0的进行修改  
  288.                 break;  
  289.             case 403:  
  290.                 System.out.println("下载403错误代码,资源不可用" + urlString);                
  291.                 //TODO 此处添加对mongodb数据库的操作,将该url的isStart改为0,暂时不在进行监控,后续根据模板状态为0的进行修改  
  292.                 break;  
  293.             case 404:  
  294.                 System.out.println("下载404错误代码,无法找到指定资源地址" + urlString);  
  295.                 //TODO 此处添加对mongodb数据库的操作,将该url的isStart改为0,暂时不在进行监控,后续根据模板状态为0的进行修改  
  296.                 break;  
  297.             case 503:  
  298.                 System.out.println("下载503错误代码,服务不可用" + urlString);  
  299.                 //TODO 此处添加对mongodb数据库的操作,将该url的isStart改为0,暂时不在进行监控,后续根据模板状态为0的进行修改  
  300.                 break;  
  301.             case 504:  
  302.                 System.out.println("下载504错误代码,网关超时" + urlString);  
  303.                 //TODO 此处添加对mongodb数据库的操作,将该url的isStart改为0,暂时不在进行监控,后续根据模板状态为0的进行修改  
  304.                 break;  
  305.             }  
  306.                   
  307.         } catch (MalformedURLException e) {  
  308.             //执行URL url = new URL()的异常  
  309.             e.printStackTrace();  
  310.         } catch (URISyntaxException e) {  
  311.             //执行URI uri = new URI()的异常  
  312.             e.printStackTrace();  
  313.         } catch (ClientProtocolException e) {  
  314.             // 执行httpClient.execute(httpGet)的异常  
  315.             e.printStackTrace();  
  316.         } catch (IOException e) {  
  317.             // 执行httpClient.execute(httpGet)的异常  
  318.             e.printStackTrace();  
  319.         } finally{  
  320.             if(response != null){  
  321.                 try {  
  322.                     response.close();  
  323.                 } catch (IOException e) {  
  324.                     e.printStackTrace();  
  325.                 }  
  326.             }  
  327.             httpGet.abort();    //结束后关闭httpGet请求  
  328.             /** 
  329.              * httpclient的链接有线程池管理,这里不用直接关闭 
  330.              */  
  331. //          try {//关闭连接  
  332. //              httpClient.close();  
  333. //          } catch (IOException e) {  
  334. //              e.printStackTrace();  
  335. //          }     
  336.         }  
  337.           
  338.         return src;  
  339.     }  
  340.     /** 
  341.      *  
  342.      * 方法名:createSSLClientDefault 
  343.      * 作者:zhouyh 
  344.      * 创建时间:2015-10-14 下午03:03:30 
  345.      * 描述:针对https采用SSL的方式创建httpclient 
  346.      * @return 
  347.      */  
  348.     public static CloseableHttpClient createSSLClientDefault(){       
  349.         try {             
  350.             SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(nullnew TrustStrategy(){  
  351.             //信任所有  
  352.             public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException {  
  353.                 return true;  
  354.             }}).build();  
  355.   
  356.             SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContext);  
  357.   
  358.             return HttpClients.custom().setSSLSocketFactory(sslsf).build();  
  359.   
  360.         } catch (KeyManagementException e) {  
  361.             e.printStackTrace();  
  362.         } catch (NoSuchAlgorithmException e) {  
  363.             e.printStackTrace();  
  364.         } catch (KeyStoreException e) {  
  365.             e.printStackTrace();  
  366.         }  
  367.               
  368.         return  HttpClients.createDefault();  
  369.     }  
  370.     /** 
  371.      *  
  372.      * 方法名:getCharsetFromMetaTag 
  373.      * 作者:zhouyh 
  374.      * 创建时间:2015-10-14 下午05:23:08 
  375.      * 描述:从meta标签中获取编码格式 
  376.      * @param buffer 
  377.      * @param url 
  378.      * @return 
  379.      */  
  380.     public static String getCharsetFromMetaTag(ByteArrayBuffer buffer,String url){  
  381.         String charset = null;  
  382.         String regEx = Constant.CHARSET_REGEX;  
  383.         Pattern p = Pattern.compile(regEx,  
  384.                 Pattern.CASE_INSENSITIVE);  
  385.         Matcher m = p.matcher(new String(buffer.toByteArray()));  
  386.         boolean result = m.find();  
  387.         if (result) {  
  388.             if (m.groupCount() == 1) {  
  389.                 charset = m.group(1);  
  390.             }   
  391.             System.err.println("网页 中的编码:" + charset + "\t url:" + url);  
  392.         } else {  
  393.             //出现未匹配的编码,先赋值为gbk  
  394.             charset = "gbk";  
  395.             System.out.println("字符编码未匹配到 : " + url);  
  396.         }  
  397.         return charset;  
  398.     }  
  399.     /** 
  400.      *  
  401.      * 方法名:replaceStr 
  402.      * 作者:zhouyh 
  403.      * 创建时间:2015-10-14 下午05:33:01 
  404.      * 描述:替换原网页中的特殊字符 
  405.      * @param src 
  406.      * @return 
  407.      */  
  408.     public static String replaceStr(String src){  
  409.         if (src == null || "".equals(src)) return null;  
  410.         src = src.replaceAll("<!--""");  
  411.         src = src.replaceAll("-->""");  
  412.         src = src.replaceAll("<""<");  
  413.         src = src.replaceAll(">"">");  
  414.         src = src.replaceAll(""", "\"");  
  415.         src = src.replaceAll(" "" ");  
  416.         src = src.replaceAll("&""&");  
  417.         return src;  
  418.     }  
  419.       
  420.     /** 
  421.      * 方法名:main 
  422.      * 作者:zhouyh 
  423.      * 创建时间:2015-10-14 上午08:46:47 
  424.      * 描述:main方法 
  425.      * @param args 
  426.      */  
  427.     public static void main(String[] args) {  
  428.         // TODO Auto-generated method stub  
  429.         Random random = new Random();  
  430.         int randomInt = random.nextInt(4);  
  431.         System.out.println(randomInt);  
  432. //      InfoLoad.getInfoLoadInstance().loadForString("http://weixin.sogou.com/remind/doc_list.php?callback=jQuery111006747886650961997_1446517725478&from=web&uid=B31F8214DA30BE47F750B8BE2BF0E4AA%40qq.sohu.com&start=0&num=20&wordid=237&clear=1&_=1446517725480", 0);  
  433.         InfoLoad.getInfoLoadInstance().loadForString("http://www.xinli001.com/info"0);  
  434.     }  
  435.   
  436. }  

[java] view plain copy
  1.   
这里用到了IO常用的工具类IOUtils,详细了解可以参考这篇文章NO.63 [file]IO常用工具类IOUtils(Java读文件、写文件、打Zip包)




http://blog.csdn.net/hwwzyh/article/details/39184677


package main.utils;


import java.io.IOException;  
import java.io.InputStream;  
import java.io.InterruptedIOException;  
import java.net.MalformedURLException;  
import java.net.URI;  
import java.net.URISyntaxException;  
import java.net.URL;  
import java.net.UnknownHostException;  
import java.nio.charset.Charset;  
import java.security.KeyManagementException;  
import java.security.KeyStoreException;  
import java.security.NoSuchAlgorithmException;  
import java.security.cert.CertificateException;  
import java.security.cert.X509Certificate;  
import java.util.Random;  
import java.util.regex.Matcher;  
import java.util.regex.Pattern;  
import java.util.zip.GZIPInputStream;  
  
import javax.net.ssl.SSLContext;  
import javax.net.ssl.SSLException;  
  
import org.apache.http.Header;  
import org.apache.http.HeaderElement;  
import org.apache.http.HttpEntity;  
import org.apache.http.HttpEntityEnclosingRequest;  
import org.apache.http.HttpHost;  
import org.apache.http.HttpRequest;  
import org.apache.http.client.ClientProtocolException;  
import org.apache.http.client.HttpRequestRetryHandler;  
import org.apache.http.client.config.CookieSpecs;  
import org.apache.http.client.config.RequestConfig;  
import org.apache.http.client.methods.CloseableHttpResponse;  
import org.apache.http.client.methods.HttpGet;  
import org.apache.http.client.protocol.HttpClientContext;  
import org.apache.http.conn.ConnectTimeoutException;  
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;  
import org.apache.http.entity.ContentType;  
import org.apache.http.impl.client.CloseableHttpClient;  
import org.apache.http.impl.client.HttpClients;  
import org.apache.http.impl.client.LaxRedirectStrategy;  
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;  
import org.apache.http.protocol.HttpContext;  
import org.apache.http.ssl.SSLContextBuilder;  
import org.apache.http.ssl.TrustStrategy;  
import org.apache.http.util.ByteArrayBuffer;  
  
  
/** 
 * 类名: InfoLoad 
 * 包名: com.boryou.module.load 
 * 作者: zhouyh 
 * 时间: 2015-10-14 上午08:46:47 
 * 描述: 下载基础类,共监控、下载等模块使用  
 */  
public class InfoLoad {  
    // 创建httpclient连接池  
    private PoolingHttpClientConnectionManager httpClientConnectionManager = null;  
      
    /******单例模式声明开始******/  
    //类初始化时,自动实例化,饿汉单例模式  
    private static final InfoLoad infoLoad = new InfoLoad();  
    /** 
     *  
     * 方法名:getInfoLoadInstance 
     * 作者:zhouyh 
     * 创建时间:2015-10-14 上午08:59:54 
     * 描述:单例的静态方法,返回InfoLoad的实例 
     * @return 
     */  
    public static InfoLoad getInfoLoadInstance(){  
        return infoLoad;  
    }  
    /******单例模式声明结束******/  
    /** 
     * 私有的构造函数 
     */  
    private InfoLoad(){  
        //初始化httpClient  
        initHttpClient();  
    }  
    /** 
     *  
     * 方法名:initHttpClient 
     * 作者:zhouyh 
     * 创建时间:2015-10-14 上午11:00:30 
     * 描述:创建httpclient连接池,并初始化httpclient 
     */  
    public void initHttpClient(){  
        //创建httpclient连接池  
        httpClientConnectionManager = new PoolingHttpClientConnectionManager();  
        //设置连接池最大数量  
        httpClientConnectionManager.setMaxTotal(5000);  
        //设置单个路由最大连接数量  
        httpClientConnectionManager.setDefaultMaxPerRoute(5000);  
    }  
    //请求重试机制  
    HttpRequestRetryHandler myRetryHandler = new HttpRequestRetryHandler() {  
        public boolean retryRequest(IOException exception, int executionCount, HttpContext context) {  
            if (executionCount >= 3) {  
                // 超过三次则不再重试请求  
                return false;  
            }  
            if (exception instanceof InterruptedIOException) {  
                // Timeout  
                return false;  
            }  
            if (exception instanceof UnknownHostException) {  
                // Unknown host  
                return false;  
            }  
            if (exception instanceof ConnectTimeoutException) {  
                // Connection refused  
                return false;             
            }  
            if (exception instanceof SSLException) {  
                // SSL handshake exception  
                return false;  
            }  
            HttpClientContext clientContext = HttpClientContext.adapt(context);  
            HttpRequest request = clientContext.getRequest();  
            boolean idempotent = !(request instanceof HttpEntityEnclosingRequest);  
            if (idempotent) {  
                // Retry if the request is considered idempotent  
                return true;  
            }  
            return false;  
        }  
    };  
    /** 
     *  
     * 方法名:getHttpClient 
     * 作者:zhouyh 
     * 创建时间:2016-2-18 下午01:23:32 
     * 描述:多线程调用时,需要创建自己的httpclient 
     * @return 
     */  
    public CloseableHttpClient getHttpClient(){       
        // 创建全局的requestConfig  
        RequestConfig requestConfig = RequestConfig.custom()  
                .setConnectTimeout(3000)  
                .setSocketTimeout(2000)  
                .setCookieSpec(CookieSpecs.BEST_MATCH).build();  
        // 声明重定向策略对象  
        LaxRedirectStrategy redirectStrategy = new LaxRedirectStrategy();  
          
        CloseableHttpClient httpClient = HttpClients.custom().setConnectionManager(httpClientConnectionManager)  
                                                    .setDefaultRequestConfig(requestConfig)  
                                                    .setRedirectStrategy(redirectStrategy)  
                                                    .setRetryHandler(myRetryHandler)  
                                                    .build();     
        return httpClient;   
    }  
      
    /** 
     *  
     * 方法名:loadForString 
     * 作者:zhouyh 
     * 创建时间:2015-10-14 下午02:22:19 
     * 描述:根据传入的url获取下载信息 
     * @param url 
     * @param type 
     * @return 
     */  
    public static String loadForString(String urlString, int type){  
        String src = "";  
        if(null==urlString || urlString.isEmpty() || !urlString.startsWith("http")){//如果urlString为null或者urlString为空,或urlString非http开头,返回src空值  
            return src;  
        }  
        //创建response  
        CloseableHttpResponse response = null;  
        HttpGet httpGet = null;  
        urlString = urlString.trim();//防止传入的urlString首尾有空格  
        //转化String url为URI,解决url中包含特殊字符的情况  
        try {  
            URL url = new URL(urlString);  
            URI uri = new URI(url.getProtocol(), url.getHost(), url.getPath(), url.getQuery(), null);  
            httpGet = new HttpGet(uri);  
            //针对https采用SSL的方式创建httpclient  
//          if(urlString.startsWith("https")){  
//              httpClient = createSSLClientDefault();  
//              System.setProperty ("jsse.enableSNIExtension", "false");  
//          }  
            //设置请求头  
            httpGet.addHeader("Accept","*/*");  
//          httpGet.addHeader("Content-Type","application/x-www-form-urlencoded; charset=UTF-8");  
            httpGet.addHeader("Connection","keep-alive");  
            httpGet.addHeader("Accept-Encoding", "gzip, deflate");  
              
            //设置USER_AGENT  
            Random random = new Random();  
            int randomInt = random.nextInt(4);  
            System.err.println(randomInt);  
              
            httpGet.addHeader("User-Agent", "Moliza");  
            //此处的代理暂时注释  
//          String[] proxys = Constant.HTTPCLIENT_PROXY[randomInt].split("\\s+");  
//          //添加代理  
//          HttpHost proxy = new HttpHost(proxys[0].trim(), Integer.parseInt(proxys[1].trim()), "http");  
//          RequestConfig config = RequestConfig.custom().setProxy(proxy).build();  
//          httpGet.setConfig(config);    
            //执行请求        
            try {  
                if(urlString.startsWith("https")){  
                    System.setProperty ("jsse.enableSNIExtension", "false");  
                    response = createSSLClientDefault().execute(httpGet);  
                }else{  
                    response = infoLoad.getHttpClient().execute(httpGet);  
                }  
            } catch (Exception e) {  
                e.printStackTrace();  
            }  
              
            //得到响应状态码  
            int statuCode = response.getStatusLine().getStatusCode();  
            //根据状态码进行逻辑处理  
            switch (statuCode){  
            case 200:  
                //获得响应实体  
                HttpEntity entity = response.getEntity();  
                /**  
                 * 仿浏览器获取网页编码  
                 * 浏览器是先从content-type的charset(响应头信息)中获取编码,  
                 * 如果获取不了,则会从meta(HTML里的代码)中获取charset的编码值  
                 */  
                //第一步-->处理网页字符编码  
                String charset = null;  
                ContentType contentType = null;  
                contentType = ContentType.getOrDefault(entity);  
                Charset charsets = contentType.getCharset();  
                if(null != charsets){  
                    charset = charsets.toString();  
                }  
                //判断返回的数据流是否采用了gzip压缩  
                Header header = entity.getContentEncoding();  
                boolean isGzip = false;  
                if(null != header){  
                    for(HeaderElement headerElement : header.getElements()){  
                        if(headerElement.getName().equalsIgnoreCase("gzip")){  
                            isGzip = true;  
                        }  
                    }  
                }  
                //获得响应流  
                InputStream inputStream = entity.getContent();  
                ByteArrayBuffer buffer = new ByteArrayBuffer(4096);  
                byte[] tmp = new byte[4096];  
                int count;  
                if(isGzip){//如果采用了Gzip压缩,则进行gizp压缩处理  
                    GZIPInputStream gzipInputStream = new GZIPInputStream(inputStream);  
                    while((count=gzipInputStream.read(tmp)) != -1){  
                        buffer.append(tmp, 0, count);  
                    }  
                }else{//处理非gzip格式的数据  
                    while((count=inputStream.read(tmp)) != -1){  
                        buffer.append(tmp, 0, count);  
                    }  
                }  
                //第二步--->如果第一步contenttyp未获取到编码,这里从meta标签中获取  
                if(null==charset || "".equals(charset) || "null".equals(charset)   
                        || "zh-cn".equalsIgnoreCase(charset)){  
                    charset = getCharsetFromMetaTag(buffer, urlString);  
                }  
                //根据获取的字符编码转为string类型  
                src = new String(buffer.toByteArray(), charset);  
                //替换特殊编码  
                src = replaceStr(src);  
                //转化Unicode编码格式]  
                //src = Common.decodeUnicode(src);  
//              System.out.println(src);  
                break;  
            case 400:  
                System.out.println("下载400错误代码,请求出现语法错误" + urlString);  
                //TODO 要进行判断是列表页还是正文页下载,再去修改数据库,下同  
                //TODO 此处添加对mongodb数据库的操作,将该url的isStart改为0,暂时不在进行监控,后续根据模板状态为0的进行修改  
                break;  
            case 403:  
                System.out.println("下载403错误代码,资源不可用" + urlString);                
                //TODO 此处添加对mongodb数据库的操作,将该url的isStart改为0,暂时不在进行监控,后续根据模板状态为0的进行修改  
                break;  
            case 404:  
                System.out.println("下载404错误代码,无法找到指定资源地址" + urlString);  
                //TODO 此处添加对mongodb数据库的操作,将该url的isStart改为0,暂时不在进行监控,后续根据模板状态为0的进行修改  
                break;  
            case 503:  
                System.out.println("下载503错误代码,服务不可用" + urlString);  
                //TODO 此处添加对mongodb数据库的操作,将该url的isStart改为0,暂时不在进行监控,后续根据模板状态为0的进行修改  
                break;  
            case 504:  
                System.out.println("下载504错误代码,网关超时" + urlString);  
                //TODO 此处添加对mongodb数据库的操作,将该url的isStart改为0,暂时不在进行监控,后续根据模板状态为0的进行修改  
                break;  
            }  
                  
        } catch (MalformedURLException e) {  
            //执行URL url = new URL()的异常  
            e.printStackTrace();  
        } catch (URISyntaxException e) {  
            //执行URI uri = new URI()的异常  
            e.printStackTrace();  
        } catch (ClientProtocolException e) {  
            // 执行httpClient.execute(httpGet)的异常  
            e.printStackTrace();  
        } catch (IOException e) {  
            // 执行httpClient.execute(httpGet)的异常  
            e.printStackTrace();  
        } finally{  
            if(response != null){  
                try {  
                    response.close();  
                } catch (IOException e) {  
                    e.printStackTrace();  
                }  
            }  
            httpGet.abort();    //结束后关闭httpGet请求  
            /** 
             * httpclient的链接有线程池管理,这里不用直接关闭 
             */  
//          try {//关闭连接  
//              httpClient.close();  
//          } catch (IOException e) {  
//              e.printStackTrace();  
//          }     
        }  
          
        return src;  
    }  
    /** 
     *  
     * 方法名:createSSLClientDefault 
     * 作者:zhouyh 
     * 创建时间:2015-10-14 下午03:03:30 
     * 描述:针对https采用SSL的方式创建httpclient 
     * @return 
     */  
    public static CloseableHttpClient createSSLClientDefault(){       
        try {             
            SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, new TrustStrategy(){  
            //信任所有  
            public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException {  
                return true;  
            }}).build();  
  
            SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContext);  
  
            return HttpClients.custom().setSSLSocketFactory(sslsf).build();  
  
        } catch (KeyManagementException e) {  
            e.printStackTrace();  
        } catch (NoSuchAlgorithmException e) {  
            e.printStackTrace();  
        } catch (KeyStoreException e) {  
            e.printStackTrace();  
        }  
              
        return  HttpClients.createDefault();  
    }  
    /** 
     *  
     * 方法名:getCharsetFromMetaTag 
     * 作者:zhouyh 
     * 创建时间:2015-10-14 下午05:23:08 
     * 描述:从meta标签中获取编码格式 
     * @param buffer 
     * @param url 
     * @return 
     */  
    public static String getCharsetFromMetaTag(ByteArrayBuffer buffer,String url){  
        String charset = null;  
        String regEx = "";//Constant.CHARSET_REGEX;  
        Pattern p = Pattern.compile(regEx,  
                Pattern.CASE_INSENSITIVE);  
        Matcher m = p.matcher(new String(buffer.toByteArray()));  
        boolean result = m.find();  
        if (result) {  
            if (m.groupCount() == 1) {  
                charset = m.group(1);  
            }   
            System.err.println("网页 中的编码:" + charset + "\t url:" + url);  
        } else {  
            //出现未匹配的编码,先赋值为gbk  
            charset = "gbk";  
            System.out.println("字符编码未匹配到 : " + url);  
        }  
        return charset;  
    }  
    /** 
     *  
     * 方法名:replaceStr 
     * 作者:zhouyh 
     * 创建时间:2015-10-14 下午05:33:01 
     * 描述:替换原网页中的特殊字符 
     * @param src 
     * @return 
     */  
    public static String replaceStr(String src){  
        if (src == null || "".equals(src)) return null;  
        src = src.replaceAll("<!--", "");  
        src = src.replaceAll("-->", "");  
        src = src.replaceAll("<", "<");  
        src = src.replaceAll(">", ">");  
        src = src.replaceAll("\"", "\\\"");  
        src = src.replaceAll(" ", " ");  
        src = src.replaceAll("&", "&");  
        return src;  
    }  
      
    /** 
     * 方法名:main 
     * 作者:zhouyh 
     * 创建时间:2015-10-14 上午08:46:47 
     * 描述:main方法 
     * @param args 
     */  
    public static void main(String[] args) {  
        // TODO Auto-generated method stub  
        Random random = new Random();  
        int randomInt = random.nextInt(4);  
        System.out.println(randomInt);  
//      InfoLoad.getInfoLoadInstance().loadForString("http://weixin.sogou.com/remind/doc_list.php?callback=jQuery111006747886650961997_1446517725478&from=web&uid=B31F8214DA30BE47F750B8BE2BF0E4AA%40qq.sohu.com&start=0&num=20&wordid=237&clear=1&_=1446517725480", 0);  
        InfoLoad.getInfoLoadInstance().loadForString("http://www.xinli001.com/info", 0);  
    }  
  

原创粉丝点击