httpclient的api变化很快,本篇随笔记录自己使用4.3.6版本时所做的设置。版本虽然不是最新,但达到了目的就行。
maven依赖:
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.3.6</version>
</dependency>
请求设置的方法:
//4.3版本不设置超时的话,一旦服务器没有响应,等待时间N久(>24小时) RequestConfig requestConfig = RequestConfig.custom() .setConnectTimeout(20000) //建立连接超时时间
.setSocketTimeout(10000) //获取数据超时 .setConnectionRequestTimeout(10000) //从连接池中取出的时间 .setCookieSpec(CookieSpecs.BEST_MATCH) //cookie的识别方式,还有浏览器兼容、标准方式、不管理使用cookie等方式
.build();
在使用时发现如果将cookieSpec设置为标准可能会提示识别不了XSRF-TOKEN等cookie,而使用最佳匹配没有问题。
设置支持https请求:
private SSLConnectionSocketFactory getSSLSF(){ SSLContextBuilder builder = new SSLContextBuilder(); // builder.loadTrustMaterial(null, new TrustSelfSignedStrategy()); try { builder.loadTrustMaterial(null, new TrustStrategy(){ public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException { return true; } }); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } catch (KeyStoreException e) { e.printStackTrace(); } SSLConnectionSocketFactory sslsf = null; try { sslsf = new SSLConnectionSocketFactory(builder.build(),SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } catch (KeyManagementException e) { e.printStackTrace(); } return sslsf; }
//httpClient.setSSLSocketFactory(sslsf)或者通过连接管理器来设置setConnectionManager(使用下面的代码给连接池管理器设置使用http/https)
private PoolingHttpClientConnectionManager getConnectionManager(SSLConnectionSocketFactory sslsf){ Registry<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory>create() .register("http", new PlainConnectionSocketFactory()) .register("https", sslsf) .build(); PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager(registry); //org.apache.http.conn.ConnectionPoolTimeoutException: Timeout waiting for connection from pool //出现大量上述异常不是连接池不够大,可能是maxPerRoute的值太小了,或者是没有释放资源,The fix is, the response entity need to be consumed. cm.setMaxTotal(2000);//max connection cm.setDefaultMaxPerRoute(200);//该值默认较小,表示对每个目标地址的连接数不超过200//(目前只有一个路由,因此可以让他等于最大值) //另外设置http client的重试次数,默认是3次;当前是禁用掉(如果项目用不到,这个默认即可) //httpClient.setHttpRequestRetryHandler(new DefaultHttpRequestRetryHandler(0, false)); //cm.closeExpiredConnections(); return cm; }
设置httpclient可随时切换代理地址
client.setRoutePlanner (HttpRoutePlanner routePlanner)
public class DynamicProxyRoutePlanner implements HttpRoutePlanner { private DefaultRoutePlanner planner = null; /** * @param host 为null时不使用代理 */ public DynamicProxyRoutePlanner(HttpHost host){ if(host==null){ planner=new DefaultRoutePlanner(DefaultSchemePortResolver.INSTANCE); }else planner = new DefaultProxyRoutePlanner(host); } /** * change proxy * @param host apply null for not using proxy */ public void setProxy(HttpHost host){ if(host==null){ planner=new DefaultRoutePlanner(DefaultSchemePortResolver.INSTANCE); }else planner = new DefaultProxyRoutePlanner(host); } //Override 接口中的方法实现 public HttpRoute determineRoute(HttpHost target, HttpRequest request, HttpContext context) throws HttpException { return planner.determineRoute(target, request, context); } }
切换代理时使用routePlanner.setProxy(httpHost);
控制CookieStore
你也许想对cookie进行持久存储,或做更多的控制,可以通过实现CookieStore接口或继承BasicCookieStore。
如获取cookie字符串:
public class MyCookieStore extends BasicCookieStore{ //用于在setHeader中整个替换,向服务器发送的cookie只包括键和值而不包括失效日期等。 @Override public synchronized String toString() { StringBuilder builder = new StringBuilder(); for (Cookie c :super.getCookies()) { builder.append(c.getName()).append("=") .append(c.getValue()).append("; "); } if(builder.length()==0) return null; return builder.substring(0,builder.length()-2).toString(); } }
转成JSON格式的字符串,用于保存和恢复:
//先写一个类用于转换,使用了FastJSON (你可以换成其他的工具) public class CookieMapper { public Cookie toCookie(JSONObject jsonObject) throws JSONException { BasicClientCookie2 cookie = new BasicClientCookie2(jsonObject.getString("name"), jsonObject.getString("value")); cookie.setComment(jsonObject.getString("comment")); cookie.setCommentURL(jsonObject.getString("commentURL")); cookie.setDomain(jsonObject.getString("domain")); cookie.setPath(jsonObject.getString("path")); cookie.setSecure(jsonObject.getBooleanValue("secure")); cookie.setVersion(jsonObject.getIntValue("version")); Long timeLong=jsonObject.getLong("expiryDate"); if(timeLong != null)//注意getLong返回的对象可能为空,而getLongValue可以返回0 cookie.setExpiryDate(new Date(timeLong)); if (jsonObject.containsKey("ports")) { cookie.setPorts(JSONArrayToArray(jsonObject.getJSONArray("ports"))); } return cookie; } public JSONObject toJSONObject(Cookie cookie) throws JSONException { JSONObject jsonObject = new JSONObject(); jsonObject.put("name", cookie.getName()); jsonObject.put("value", cookie.getValue()); jsonObject.put("comment", cookie.getComment()); jsonObject.put("commentURL", cookie.getCommentURL()); jsonObject.put("domain", cookie.getDomain()); jsonObject.put("path", cookie.getPath()); jsonObject.put("secure", cookie.isSecure()); jsonObject.put("version", cookie.getVersion()); if (cookie.getExpiryDate() != null) { jsonObject.put("expiryDate", cookie.getExpiryDate().getTime()); } if (cookie.getPorts() != null) { JSONArray jsonArray = arrayToJSONArray(cookie.getPorts()); jsonObject.put("ports", jsonArray); } return jsonObject; } private JSONArray arrayToJSONArray(int[] ports) { JSONArray jsonArray = new JSONArray(); for(int i = 0 ; i < ports.length; i++){ jsonArray.add(ports[i]); } return jsonArray; } private int[] JSONArrayToArray(JSONArray jsonArray) throws JSONException { int size=jsonArray.size(); int[] ports = new int[size]; for(int i = 0 ; i < size; i++){ ports[i] = jsonArray.getInteger(i); } return ports; } }
使用下面的方法对Cookie与String进行相互转换:
private String toJsonString(List<Cookie> cookies) { CookieMapper cookieMapper = new CookieMapper(); try { JSONArray jsonArray = new JSONArray(); for (Cookie cookie1 : cookies) { jsonArray.add(cookieMapper.toJSONObject(cookie1)); } return jsonArray.toString(); } catch (Exception e) { throw new RuntimeException(e.getMessage()); } } private Cookie[] getCookiesFromStore(String jsonStr) { if (jsonStr==null || jsonStr.equals("")) { return new Cookie[0]; } CookieMapper cookieMapper = new CookieMapper(); try { JSONArray jsonArray = JSONArray.parseArray(jsonStr); List<Cookie> cookies = new ArrayList<Cookie>(jsonArray.size()); for (int i = 0; i < jsonArray.size(); i++) { JSONObject jsonObject = jsonArray.getJSONObject(i); cookies.add(cookieMapper.toCookie(jsonObject)); } return cookies.toArray(new Cookie[0]); } catch (Exception e) { e.printStackTrace(); throw new RuntimeException(e.getMessage()); } }
client.setDefaultCookieStore来设置httpclient使用自己的cookieStore