轻松把玩HttpClient之封装HttpClient工具类(六),封装输入参数,简化工具类

最后更新于:2022-04-01 23:00:06

     版权声明:本文为博主原创文章,未经博主允许不得转载。如需转载请声明:【转自 http://blog.csdn.net/xiaoxian8023 】      在写这个工具类的时候发现传入的参数太多,以至于方法泛滥,只一个send方法就有30多个,所以对工具类进行了优化,把输入参数封装在一个对象里,这样以后再扩展输入参数,直接修改这个类就ok了。      不多说了,先上代码: ~~~ /** * 请求配置类 * * @author arron * @date 2016年2月2日 下午3:14:32 * @version 1.0 */ public class HttpConfig { private HttpConfig(){}; /** * 获取实例 * @return */ public static HttpConfig custom(){ return new HttpConfig(); } /** * HttpClient对象 */ private HttpClient client; /** * CloseableHttpAsyncClient对象 */ private CloseableHttpAsyncClient asynclient; /** * 资源url */ private String url; /** * Header头信息 */ private Header[] headers; /** * 请求方法 */ private HttpMethods method=HttpMethods.GET; /** * 请求方法名称 */ private String methodName; /** * 用于cookie操作 */ private HttpContext context; /** * 传递参数 */ private Map map; /** * 输入输出编码 */ private String encoding=Charset.defaultCharset().displayName(); /** * 输入编码 */ private String inenc; /** * 输出编码 */ private String outenc; /** * 输出流对象 */ private OutputStream out; /** * 异步操作回调执行器 */ private IHandler handler; /** * HttpClient对象 */ public HttpConfig client(HttpClient client) { this.client = client; return this; } /** * CloseableHttpAsyncClient对象 */ public HttpConfig asynclient(CloseableHttpAsyncClient asynclient) { this.asynclient = asynclient; return this; } /** * 资源url */ public HttpConfig url(String url) { this.url = url; return this; } /** * Header头信息 */ public HttpConfig headers(Header[] headers) { this.headers = headers; return this; } /** * 请求方法 */ public HttpConfig method(HttpMethods method) { this.method = method; return this; } /** * 请求方法 */ public HttpConfig methodName(String methodName) { this.methodName = methodName; return this; } /** * cookie操作相关 */ public HttpConfig context(HttpContext context) { this.context = context; return this; } /** * 传递参数 */ public HttpConfig map(Map map) { this.map = map; return this; } /** * 输入输出编码 */ public HttpConfig encoding(String encoding) { //设置输入输出 inenc(encoding); outenc(encoding); this.encoding = encoding; return this; } /** * 输入编码 */ public HttpConfig inenc(String inenc) { this.inenc = inenc; return this; } /** * 输出编码 */ public HttpConfig outenc(String outenc) { this.outenc = outenc; return this; } /** * 输出流对象 */ public HttpConfig out(OutputStream out) { this.out = out; return this; } /** * 异步操作回调执行器 */ public HttpConfig handler(IHandler handler) { this.handler = handler; return this; } public HttpClient client() { return client; } public CloseableHttpAsyncClient asynclient() { return asynclient; } public Header[] headers() { return headers; } public String url() { return url; } public HttpMethods method() { return method; } public String methodName() { return methodName; } public HttpContext context() { return context; } public Map map() { return map; } public String encoding() { return encoding; } public String inenc() { return inenc == null ? encoding : inenc; } public String outenc() { return outenc == null ? encoding : outenc; } public OutputStream out() { return out; } public IHandler handler() { return handler; } } ~~~      将构造方法设置为private,然后提供一个custom()方法来获取新的实例,所有的set方法,都是返回HttpConfig,这样就支持链式调用(创建者模式)了。      工具类的核心方法如下: ~~~ /** * 请求资源或服务 * * @param config * @return * @throws HttpProcessException */ public static String send(HttpConfig config) throws HttpProcessException { return fmt2String(execute(config), config.outenc()); } /** * 请求资源或服务 * * @param client client对象 * @param url 资源地址 * @param httpMethod 请求方法 * @param parasMap 请求参数 * @param headers 请求头信息 * @param encoding 编码 * @return 返回处理结果 * @throws HttpProcessException */ private static HttpResponse execute(HttpConfig config) throws HttpProcessException { if(config.client()==null){//检测是否设置了client config.client(create(config.url())); } HttpResponse resp = null; try { //创建请求对象 HttpRequestBase request = getRequest(config.url(), config.method()); //设置header信息 request.setHeaders(config.headers()); //判断是否支持设置entity(仅HttpPost、HttpPut、HttpPatch支持) if(HttpEntityEnclosingRequestBase.class.isAssignableFrom(request.getClass())){ List nvps = new ArrayList(); //检测url中是否存在参数 config.url(Utils.checkHasParas(config.url(), nvps, config.inenc())); //装填参数 HttpEntity entity = Utils.map2List(nvps, config.map(), config.inenc()); //设置参数到请求对象中 ((HttpEntityEnclosingRequestBase)request).setEntity(entity); logger.info("请求地址:"+config.url()); if(nvps.size()>0){ logger.info("请求参数:"+nvps.toString()); } }else{ int idx = config.url().indexOf("?"); logger.info("请求地址:"+config.url().substring(0, (idx>0 ? idx : config.url().length()))); if(idx>0){ logger.info("请求参数:"+config.url().substring(idx+1)); } } //执行请求操作,并拿到结果(同步阻塞) resp = (config.context()==null)?config.client().execute(request) : config.client().execute(request, config.context()) ; //获取结果实体 return resp; } catch (IOException e) { throw new HttpProcessException(e); } } //-----------华----丽----分----割----线-------------- //-----------华----丽----分----割----线-------------- //-----------华----丽----分----割----线-------------- /** * 转化为字符串 * * @param entity 实体 * @param encoding 编码 * @return * @throws HttpProcessException */ public static String fmt2String(HttpResponse resp, String encoding) throws HttpProcessException { String body = ""; try { if (resp.getEntity() != null) { // 按指定编码转换结果实体为String类型 body = EntityUtils.toString(resp.getEntity(), encoding); logger.debug(body); } EntityUtils.consume(resp.getEntity()); } catch (ParseException | IOException e) { throw new HttpProcessException(e); }finally{ close(resp); } return body; } /** * 转化为流 * * @param entity 实体 * @param out 输出流 * @return * @throws HttpProcessException */ public static OutputStream fmt2Stream(HttpResponse resp, OutputStream out) throws HttpProcessException { try { resp.getEntity().writeTo(out); EntityUtils.consume(resp.getEntity()); } catch (ParseException | IOException e) { throw new HttpProcessException(e); }finally{ close(resp); } return out; } ~~~      再附上测试代码: ~~~ public static void testOne() throws HttpProcessException{ System.out.println("--------简单方式调用(默认post)--------"); String url = "http://tool.oschina.net/"; HttpConfig config = HttpConfig.custom(); //简单调用 String resp = HttpClientUtil.get(config.url(url)); System.out.println("请求结果内容长度:"+ resp.length()); System.out.println("\n#################################\n"); System.out.println("--------加入header设置--------"); url="http://blog.csdn.net/xiaoxian8023"; //设置header信息 Header[] headers=HttpHeader.custom().userAgent("Mozilla/5.0").build(); //执行请求 resp = HttpClientUtil.get(config.headers(headers)); System.out.println("请求结果内容长度:"+ resp.length()); System.out.println("\n#################################\n"); System.out.println("--------代理设置(绕过证书验证)-------"); url="https://www.facebook.com/"; HttpClient client= HCB.custom().timeout(10000).proxy("127.0.0.1", 8087).ssl().build();//采用默认方式(绕过证书验证) //执行请求 resp = HttpClientUtil.get(config.client(client)); System.out.println("请求结果内容长度:"+ resp.length()); System.out.println("\n#################################\n"); // System.out.println("--------代理设置(自签名证书验证)+header+get方式-------"); // url = "https://sso.tgb.com:8443/cas/login"; // client= HCB.custom().timeout(10000).ssl("D:\\keys\\wsriakey","tomcat").build(); // headers=HttpHeader.custom().keepAlive("false").connection("close").contentType(Headers.APP_FORM_URLENCODED).build(); // //执行请求 // resp = CopyOfHttpClientUtil.get(config.method(HttpMethods.GET)); // System.out.println("请求结果内容长度:"+ resp.length()); try { System.out.println("--------下载测试-------"); url="http://ss.bdimg.com/static/superman/img/logo/logo_white_fe6da1ec.png"; FileOutputStream out = new FileOutputStream(new File("d://aaa//000.png")); HttpClientUtil.down(HttpConfig.custom().url(url).out(out)); out.flush(); out.close(); System.out.println("--------下载测试+代理-------"); out = new FileOutputStream(new File("d://aaa//001.png")); HttpClientUtil.down(HttpConfig.custom().client(client).url(url).out(out)); out.flush(); out.close(); } catch (IOException e) { e.printStackTrace(); } System.out.println("\n#################################\n"); } ~~~      可以看到这样调用会更显得清晰明了。以后再添加功能时,改起来也会比较方便了。工具类也提供了输出流的功能,可以用于下载文件或者加载验证码图片,非常方便。      最新的完整代码请到GitHub上进行下载:https://github.com/Arronlong/httpclientUtil 。
';

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

最后更新于:2022-04-01 23:00:04

     版权声明:本文为博主原创文章,未经博主允许不得转载。如需转载请声明:【转自 http://blog.csdn.net/xiaoxian8023 】      最近更新了一下[HttpClientUtil工具类](https://github.com/Arronlong/httpclientUtil)代码,主要是添加了一个参数HttpContext,这个是用来干嘛的呢?其实是用来保存和传递Cookie所需要的。因为我们有很多时候都需要登录,然后才能请求一些想要的数据。而在这以前使用HttpClientUtil工具类,还不能办到。现在更新了以后,终于可以了。      先说一下思路:本次的demo,就是获取csdn中的c币,要想获取c币,必须先登录。而每次登录需要5个参数。其中2个必不可少的参数是用户名和密码,其他的3个参数,是需要从登录页面获取的。在第一次请求登录页面,只要设置了CookieStore,就可以自动获取cookie了,然后从返回的html源码中获取参数,再组装添加用户名密码,然后第二次登录,如果返回的html源码中有“帐号登录”这几个字,就说明登录失败了。否则登录成功。可以打印一下cookie(已注释)。然后再访问c币查询的页面,就可以从返回的html源码中解析到c币的值了。登录时需要注意的是:直接提交用户名密码或者第二次登录不携带context参数,是不能登录成功的。      具体代码如下: ~~~ public static void main(String[] args) throws HttpProcessException { //登录地址 String loginUrl = "https://passport.csdn.net/account/login"; //C币查询 String scoreUrl = "http://my.csdn.net/my/score"; HttpClientContext context = new HttpClientContext(); CookieStore cookieStore = new BasicCookieStore(); context.setCookieStore(cookieStore); //获取参数 String loginform = HttpClientUtil.send(loginUrl, context); // System.out.println(loginform); System.out.println("获取登录所需参数"); String lt = regex("\"lt\" value=\"([^\"]*)\"", loginform)[0]; String execution = regex("\"execution\" value=\"([^\"]*)\"", loginform)[0]; String _eventId = regex("\"_eventId\" value=\"([^\"]*)\"", loginform)[0]; //组装参数 Map map = new HashMap(); map.put("username", "用户名"); map.put("password", "密码"); map.put("lt", lt); map.put("execution", execution); map.put("_eventId", _eventId); //发送登录请求 String result = HttpClientUtil.send(loginUrl, map, context); // System.out.println(result); if(result.contains("帐号登录")){//如果有帐号登录,则说明未登录成功 String errmsg = regex("\"error-message\">([^<]*)<", result)[0]; System.err.println("登录失败:"+errmsg); return; } System.out.println("----登录成功----"); // //打印参数,可以看到cookie里已经有值了。 // cookieStore = context.getCookieStore(); // for (Cookie cookie : cookieStore.getCookies()) { // System.out.println(cookie.getName()+"--"+cookie.getValue()); // } //访问积分管理页面 Header[] headers = HttpHeader.custom().userAgent("Mozilla/5.0").build(); result = HttpClientUtil.send(scoreUrl, headers, context); //获取C币 String score = regex("\"last-img\">([^<]*)<", result)[0]; System.out.println("您当前有C币:"+score); } ~~~      从html源码中解析参数和c币值所用到的一个方法: ~~~ /** * 通过正则表达式获取内容 * * @param regex 正则表达式 * @param from 原字符串 * @return */ public static String[] regex(String regex, String from){ Pattern pattern = Pattern.compile(regex); Matcher matcher = pattern.matcher(from); List results = new ArrayList(); while(matcher.find()){ for (int i = 0; i < matcher.groupCount(); i++) { results.add(matcher.group(i+1)); } } return results.toArray(new String[]{}); } ~~~      测试结果: ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-02-18_56c53cb865fff.jpg) ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-02-18_56c53cb876cee.jpg)      最重要的就是context这个参数了,给它设置了cookiestore,那么会在每次请求时将cookie带入请求中。或者也可以在header中手动设置cookie参数,也是可以做到的。
';

轻松把玩HttpAsyncClient之模拟post请求示例

最后更新于:2022-04-01 23:00:02

     版权声明:本文为博主原创文章,未经博主允许不得转载。如需转载请声明:【转自 http://blog.csdn.net/xiaoxian8023 】      如果看到过我前些天写过的《[轻松把玩HttpClient之模拟post请求示例](http://blog.csdn.net/xiaoxian8023/article/details/49863967)》这篇文章,你再看本文就是小菜一碟了,如果你顺便懂一些NIO,基本上是毫无压力了。因为HttpAsyncClient相对于HttpClient,就多了一个NIO,这也是为什么支持异步的原因。      不过我有一个疑问,虽说NIO是同步非阻塞IO,但是HttpAsyncClient提供了回调的机制,这点儿跟netty很像,所以可以模拟类似于AIO的效果。但是[官网上的例子](http://hc.apache.org/httpcomponents-asyncclient-4.1.x/httpasyncclient/examples/org/apache/http/examples/nio/client/AsyncClientHttpExchange.java)却基本上都是使用Future future = httpclient.execute(request, null);来同步获得执行结果。      好吧,反正我是用回调的方式实现的。代码基本上跟httpClient那篇一致。不一样的地方主要有这么2个地方:配置ssl时不一样;调用execute方式时,使用回调。具体代码如下: ~~~ package com.tgb.ccl.http.simpledemo; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.Reader; import java.security.KeyManagementException; import java.security.KeyStore; import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; import java.security.cert.CertificateException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import javax.net.ssl.SSLContext; import javax.net.ssl.TrustManager; import javax.net.ssl.X509TrustManager; import org.apache.http.HttpEntity; import org.apache.http.HttpHost; 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.entity.UrlEncodedFormEntity; import org.apache.http.client.methods.HttpPost; import org.apache.http.concurrent.FutureCallback; import org.apache.http.config.Registry; import org.apache.http.config.RegistryBuilder; import org.apache.http.conn.ssl.TrustSelfSignedStrategy; import org.apache.http.impl.conn.DefaultProxyRoutePlanner; import org.apache.http.impl.nio.client.CloseableHttpAsyncClient; import org.apache.http.impl.nio.client.HttpAsyncClientBuilder; import org.apache.http.impl.nio.client.HttpAsyncClients; import org.apache.http.impl.nio.conn.PoolingNHttpClientConnectionManager; import org.apache.http.impl.nio.reactor.DefaultConnectingIOReactor; import org.apache.http.impl.nio.reactor.IOReactorConfig; import org.apache.http.message.BasicNameValuePair; import org.apache.http.nio.conn.NoopIOSessionStrategy; import org.apache.http.nio.conn.SchemeIOSessionStrategy; import org.apache.http.nio.conn.ssl.SSLIOSessionStrategy; import org.apache.http.nio.reactor.ConnectingIOReactor; import org.apache.http.ssl.SSLContexts; import org.apache.http.util.EntityUtils; /** * HttpAsyncClient模拟post请求简单示例 * * @author arron * @date 2015年11月1日 下午2:23:18 * @version 1.0 */ public class SimpleHttpAsyncClientDemo { /** * 设置信任自定义的证书 * * @param keyStorePath 密钥库路径 * @param keyStorepass 密钥库密码 * @return */ public static SSLContext custom(String keyStorePath, String keyStorepass) { SSLContext sc = null; FileInputStream instream = null; KeyStore trustStore = null; try { trustStore = KeyStore.getInstance(KeyStore.getDefaultType()); instream = new FileInputStream(new File(keyStorePath)); trustStore.load(instream, keyStorepass.toCharArray()); // 相信自己的CA和所有自签名的证书 sc = SSLContexts.custom().loadTrustMaterial(trustStore, new TrustSelfSignedStrategy()).build(); } catch (KeyStoreException | NoSuchAlgorithmException| CertificateException | IOException | KeyManagementException e) { e.printStackTrace(); } finally { try { instream.close(); } catch (IOException e) { } } return sc; } /** * 绕过验证 * * @return * @throws NoSuchAlgorithmException * @throws KeyManagementException */ public static SSLContext createIgnoreVerifySSL() throws NoSuchAlgorithmException, KeyManagementException { SSLContext sc = SSLContext.getInstance("SSLv3"); // 实现一个X509TrustManager接口,用于绕过验证,不用修改里面的方法 X509TrustManager trustManager = new X509TrustManager() { @Override public void checkClientTrusted( java.security.cert.X509Certificate[] paramArrayOfX509Certificate, String paramString) throws CertificateException { } @Override public void checkServerTrusted( java.security.cert.X509Certificate[] paramArrayOfX509Certificate, String paramString) throws CertificateException { } @Override public java.security.cert.X509Certificate[] getAcceptedIssuers() { return null; } }; sc.init(null, new TrustManager[] { trustManager }, null); return sc; } /** * 设置代理 * @param builder * @param hostOrIP * @param port */ public static HttpAsyncClientBuilder proxy(String hostOrIP, int port){ // 依次是代理地址,代理端口号,协议类型 HttpHost proxy = new HttpHost(hostOrIP, port, "http"); DefaultProxyRoutePlanner routePlanner = new DefaultProxyRoutePlanner(proxy); return HttpAsyncClients.custom().setRoutePlanner(routePlanner); } /** * 模拟请求 * * @param url 资源地址 * @param map 参数列表 * @param encoding 编码 * @param handler 结果处理类 * @return * @throws NoSuchAlgorithmException * @throws KeyManagementException * @throws IOException * @throws ClientProtocolException */ public static void send(String url, Map map,final String encoding, final AsyncHandler handler) throws KeyManagementException, NoSuchAlgorithmException, ClientProtocolException, IOException { //绕过证书验证,处理https请求 SSLContext sslcontext = createIgnoreVerifySSL(); // 设置协议http和https对应的处理socket链接工厂的对象 Registry sessionStrategyRegistry = RegistryBuilder.create() .register("http", NoopIOSessionStrategy.INSTANCE) .register("https", new SSLIOSessionStrategy(sslcontext)) .build(); //配置io线程 IOReactorConfig ioReactorConfig = IOReactorConfig.custom().setIoThreadCount(Runtime.getRuntime().availableProcessors()).build(); //设置连接池大小 ConnectingIOReactor ioReactor; ioReactor = new DefaultConnectingIOReactor(ioReactorConfig); PoolingNHttpClientConnectionManager connManager = new PoolingNHttpClientConnectionManager(ioReactor, null, sessionStrategyRegistry, null); //创建自定义的httpclient对象 final CloseableHttpAsyncClient client = proxy("127.0.0.1", 8087).setConnectionManager(connManager).build(); // CloseableHttpAsyncClient client = HttpAsyncClients.createDefault(); //创建post方式请求对象 HttpPost httpPost = new HttpPost(url); //装填参数 List nvps = new ArrayList(); if(map!=null){ for (Entry entry : map.entrySet()) { nvps.add(new BasicNameValuePair(entry.getKey(), entry.getValue())); } } //设置参数到请求对象中 httpPost.setEntity(new UrlEncodedFormEntity(nvps, encoding)); System.out.println("请求地址:"+url); System.out.println("请求参数:"+nvps.toString()); //设置header信息 //指定报文头【Content-type】、【User-Agent】 httpPost.setHeader("Content-type", "application/x-www-form-urlencoded"); httpPost.setHeader("User-Agent", "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt)"); // Start the client client.start(); //执行请求操作,并拿到结果(异步) client.execute(httpPost, new FutureCallback() { @Override public void failed(Exception ex) { handler.failed(ex); close(client); } @Override public void completed(HttpResponse resp) { String body=""; //这里使用EntityUtils.toString()方式时会大概率报错,原因:未接受完毕,链接已关 try { HttpEntity entity = resp.getEntity(); if (entity != null) { final InputStream instream = entity.getContent(); try { final StringBuilder sb = new StringBuilder(); final char[] tmp = new char[1024]; final Reader reader = new InputStreamReader(instream,encoding); int l; while ((l = reader.read(tmp)) != -1) { sb.append(tmp, 0, l); } body = sb.toString(); } finally { instream.close(); EntityUtils.consume(entity); } } } catch (ParseException | IOException e) { e.printStackTrace(); } handler.completed(body); close(client); } @Override public void cancelled() { handler.cancelled(); close(client); } }); } /** * 关闭client对象 * * @param client */ private static void close(CloseableHttpAsyncClient client) { try { client.close(); } catch (IOException e) { e.printStackTrace(); } } static class AsyncHandler implements IHandler{ @Override public Object failed(Exception e) { System.err.println(Thread.currentThread().getName()+"--失败了--"+e.getClass().getName()+"--"+e.getMessage()); return null; } @Override public Object completed(String respBody) { System.out.println(Thread.currentThread().getName()+"--获取内容:"+respBody); return null; } @Override public Object cancelled() { System.out.println(Thread.currentThread().getName()+"--取消了"); return null; } } /** * 回调处理接口 * * @author arron * @date 2015年11月10日 上午10:05:40 * @version 1.0 */ public interface IHandler { /** * 处理异常时,执行该方法 * @return */ Object failed(Exception e); /** * 处理正常时,执行该方法 * @return */ Object completed(String respBody); /** * 处理取消时,执行该方法 * @return */ Object cancelled(); } } ~~~      来一个测试类: ~~~ public static void main(String[] args) throws KeyManagementException, NoSuchAlgorithmException, ClientProtocolException, IOException { AsyncHandler handler = new AsyncHandler(); String url = "http://php.weather.sina.com.cn/iframe/index/w_cl.php"; Map map = new HashMap(); map.put("code", "js"); map.put("day", "0"); map.put("city", "上海"); map.put("dfc", "1"); map.put("charset", "utf-8"); send(url, map, "utf-8", handler); System.out.println("-----------------------------------"); map.put("city", "北京"); send(url, map, "utf-8", handler); System.out.println("-----------------------------------"); } ~~~      测试结果如下: ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-02-18_56c53cb8530bd.jpg)      很简单吧,其实基于HttpAsyncClient的工具类我也进行了封装,跟HttpClient工具类差不多。代码都已经提交至:[https://github.com/Arronlong/httpclientUtil](https://github.com/Arronlong/httpclientUtil)。有兴趣的自行下载,博客中就不再分享了。
';

轻松把玩HttpClient之封装HttpClient工具类(四),单线程调用及多线程批量调用测试

最后更新于:2022-04-01 23:00:00

     版权声明:本文为博主原创文章,未经博主允许不得转载。如需转载请声明:【转自 http://blog.csdn.net/xiaoxian8023 】      本文主要来分享一下该工具类的测试结果。工具类的整体源码不再单独分享,源码基本上都已经在文章中了。开始我们的测试。      单线程调用测试: ~~~ public static void testOne() throws HttpProcessException{ System.out.println("--------简单方式调用(默认post)--------"); String url = "http://tool.oschina.net/"; //简单调用 String resp = HttpClientUtil.send(url); System.out.println("请求结果内容长度:"+ resp.length()); System.out.println("\n#################################\n"); System.out.println("--------加入header设置--------"); url="http://blog.csdn.net/xiaoxian8023"; //设置header信息 Header[] headers=HttpHeader.custom().userAgent("Mozilla/5.0").build(); //执行请求 resp = HttpClientUtil.send(url, headers); System.out.println("请求结果内容长度:"+ resp.length()); System.out.println("\n#################################\n"); System.out.println("--------代理设置(绕过证书验证)-------"); url="https://www.facebook.com/"; HttpClient client= HCB.custom().timeout(10000).proxy("127.0.0.1", 8087).ssl().build();//采用默认方式(绕过证书验证) //执行请求 resp = HttpClientUtil.send(client,url); System.out.println("请求结果内容长度:"+ resp.length()); System.out.println("\n#################################\n"); System.out.println("--------代理设置(自签名证书验证)+header+get方式-------"); url = "https://sso.tgb.com:8443/cas/login"; client= HCB.custom().timeout(10000).ssl("D:\\keys\\wsriakey","tomcat").build(); headers=HttpHeader.custom().keepAlive("false").connection("close").contentType(Headers.APP_FORM_URLENCODED).build(); //执行请求 resp = HttpClientUtil.send(client, url, HttpMethods.GET, headers); System.out.println("请求结果内容长度:"+ resp.length()); System.out.println("\n#################################\n"); } ~~~      测试结果如下: ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-02-18_56c53cb8202c9.jpg)      可以看到4次调用,都没有问题。      那么现在试试多线程调用吧。我定义一个数组,里面有20篇文章的地址。我启动20个线程的线程池来测试,写了一个20*50次的for循环,看看全部线程结束时有没有报错,能用多长时间: ~~~ public static void testMutilTask(){ // URL列表数组 String[] urls = { "http://blog.csdn.net/xiaoxian8023/article/details/49862725", "http://blog.csdn.net/xiaoxian8023/article/details/49834643", "http://blog.csdn.net/xiaoxian8023/article/details/49834615", "http://blog.csdn.net/xiaoxian8023/article/details/49834589", "http://blog.csdn.net/xiaoxian8023/article/details/49785417", "http://blog.csdn.net/xiaoxian8023/article/details/48679609", "http://blog.csdn.net/xiaoxian8023/article/details/48681987", "http://blog.csdn.net/xiaoxian8023/article/details/48710653", "http://blog.csdn.net/xiaoxian8023/article/details/48729479", "http://blog.csdn.net/xiaoxian8023/article/details/48733249", "http://blog.csdn.net/xiaoxian8023/article/details/48806871", "http://blog.csdn.net/xiaoxian8023/article/details/48826857", "http://blog.csdn.net/xiaoxian8023/article/details/49663643", "http://blog.csdn.net/xiaoxian8023/article/details/49619777", "http://blog.csdn.net/xiaoxian8023/article/details/47335659", "http://blog.csdn.net/xiaoxian8023/article/details/47301245", "http://blog.csdn.net/xiaoxian8023/article/details/47057573", "http://blog.csdn.net/xiaoxian8023/article/details/45601347", "http://blog.csdn.net/xiaoxian8023/article/details/45569441", "http://blog.csdn.net/xiaoxian8023/article/details/43312929", }; // 设置header信息 Header[] headers = HttpHeader.custom().userAgent("Mozilla/5.0").build(); HttpClient client= HCB.custom().timeout(10000).build(); long start = System.currentTimeMillis(); try { int pagecount = urls.length; ExecutorService executors = Executors.newFixedThreadPool(pagecount); CountDownLatch countDownLatch = new CountDownLatch(pagecount*100); for(int i = 0; i< pagecount*100;i++){ //启动线程抓取 executors.execute(new GetRunnable(urls[i%pagecount], headers, countDownLatch).setClient(client)); } countDownLatch.await(); executors.shutdown(); } catch (InterruptedException e) { e.printStackTrace(); } finally { System.out.println("线程" + Thread.currentThread().getName() + ", 所有线程已完成,开始进入下一步!"); } long end = System.currentTimeMillis(); System.out.println("总耗时(毫秒): -> " + (end - start)); //(7715+7705+7616)/3= 23 036/3= 7 678.66---150=51.2 //(9564+8250+8038+7604+8401)/5=41 857/5=8 371.4--150 //(9803+8244+8188+8378+8188)/5=42 801/5= 8 560.2---150 } static class GetRunnable implements Runnable { private CountDownLatch countDownLatch; private String url; private Header[] headers; private HttpClient client = null; public GetRunnable setClient(HttpClient client){ this.client = client; return this; } public GetRunnable(String url, Header[] headers,CountDownLatch countDownLatch){ this.url = url; this.headers = headers; this.countDownLatch = countDownLatch; } @Override public void run() { try { String response = null; if(client!=null){ response = HttpClientUtil.send(client, url, headers); }else{ response = HttpClientUtil.send(url, headers); } System.out.println(Thread.currentThread().getName()+"--获取内容长度:"+response.length()); } catch (HttpProcessException e) { e.printStackTrace(); } finally { countDownLatch.countDown(); } } } ~~~      定义了一个ExecutorService的线程池,使用CountDownLatch来保证所有线程都运行完毕,测试一下看看: ~~~ public static void main(String[] args) throws Exception { // testOne(); testMutilTask(); } ~~~      测试结果如下: ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-02-18_56c53cb83c6b2.jpg)      从结果中可以清楚的看到执行1000次调用,总消耗是51165,平均51ms/个,速度快,而且没有报错。      好了,本工具就分享到这里,下次会分享异步的HttpClient,敬请期待。      代码已上传至:[https://github.com/Arronlong/httpclientUtil](https://github.com/Arronlong/httpclientUtil)。
';

轻松把玩HttpClient之封装HttpClient工具类(三),插件式配置Header

最后更新于:2022-04-01 22:59:57

     版权声明:本文为博主原创文章,未经博主允许不得转载。如需转载请声明:【转自 http://blog.csdn.net/xiaoxian8023 】      上篇文章介绍了插件式配置HttpClient,本文将介绍插件式配置Header。      为什么要配置header在前面已经提到了,还里再简单说一下,要使用HttpClient模拟请求,去访问各种接口或者网站资源,都有可能有各种限制,比如说java客户端模拟访问csdn博客,就必须设置User-Agent,否则就报错了。还有各种其他情况,必须的设置一些特定的Header,才能请求成功,或者才能不出问题。      好了就说这么多,本次还是采用构造者模式的级联调用方式,来完成该工具类。在该工具类中,为所有常用的Http Request Header都提供了设置方法。具体参数参考的链接是[HTTP Header 详解](http://kb.cnblogs.com/page/92320/)。      不再多废话了,看具体代码吧: ~~~ package com.tgb.ccl.http.common; import java.util.HashMap; import java.util.Map; import org.apache.http.Consts; import org.apache.http.Header; import org.apache.http.message.BasicHeader; /** * 创建HttpReqHead * * @author arron * @date 2015年11月9日 上午10:37:23 * @version 1.0 */ public class HttpHeader { private HttpHeader() {}; public static HttpHeader custom() { return new HttpHeader(); } //记录head头信息 private Map headerMaps = new HashMap(); /** * 指定客户端能够接收的内容类型 * 例如:Accept: text/plain, text/html * * @param accept */ public HttpHeader accept(String accept) { headerMaps.put(HttpReqHead.ACCEPT, new BasicHeader(HttpReqHead.ACCEPT, accept)); return this; } /** * 浏览器可以接受的字符编码集 * 例如:Accept-Charset: iso-8859-5 * * @param acceptCharset */ public HttpHeader acceptCharset(String acceptCharset) { headerMaps.put(HttpReqHead.ACCEPT_CHARSET, new BasicHeader(HttpReqHead.ACCEPT_CHARSET, acceptCharset)); return this; } /** * 指定浏览器可以支持的web服务器返回内容压缩编码类型 * 例如:Accept-Encoding: compress, gzip * * @param acceptEncoding */ public HttpHeader acceptEncoding(String acceptEncoding) { headerMaps.put(HttpReqHead.ACCEPT_ENCODING, new BasicHeader(HttpReqHead.ACCEPT_ENCODING, acceptEncoding)); return this; } /** * 浏览器可接受的语言 * 例如:Accept-Language: en,zh * * @param acceptLanguage */ public HttpHeader acceptLanguage(String acceptLanguage) { headerMaps.put(HttpReqHead.ACCEPT_LANGUAGE, new BasicHeader(HttpReqHead.ACCEPT_LANGUAGE, acceptLanguage)); return this; } /** * 可以请求网页实体的一个或者多个子范围字段 * 例如:Accept-Ranges: bytes * * @param acceptRanges */ public HttpHeader acceptRanges(String acceptRanges) { headerMaps.put(HttpReqHead.ACCEPT_RANGES, new BasicHeader(HttpReqHead.ACCEPT_RANGES, acceptRanges)); return this; } /** * HTTP授权的授权证书 * 例如:Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ== * * @param authorization */ public HttpHeader authorization(String authorization) { headerMaps.put(HttpReqHead.AUTHORIZATION, new BasicHeader(HttpReqHead.AUTHORIZATION, authorization)); return this; } /** * 指定请求和响应遵循的缓存机制 * 例如:Cache-Control: no-cache * * @param cacheControl */ public HttpHeader cacheControl(String cacheControl) { headerMaps.put(HttpReqHead.CACHE_CONTROL, new BasicHeader(HttpReqHead.CACHE_CONTROL, cacheControl)); return this; } /** * 表示是否需要持久连接(HTTP 1.1默认进行持久连接) * 例如:Connection: close 短链接; Connection: keep-alive 长连接 * * @param connection * @return */ public HttpHeader connection(String connection) { headerMaps.put(HttpReqHead.CONNECTION, new BasicHeader(HttpReqHead.CONNECTION, connection)); return this; } /** * HTTP请求发送时,会把保存在该请求域名下的所有cookie值一起发送给web服务器 * 例如:Cookie: $Version=1; Skin=new; * * @param cookie */ public HttpHeader cookie(String cookie) { headerMaps.put(HttpReqHead.COOKIE, new BasicHeader(HttpReqHead.COOKIE, cookie)); return this; } /** * 请求内容长度 * 例如:Content-Length: 348 * * @param contentLength */ public HttpHeader contentLength(String contentLength) { headerMaps.put(HttpReqHead.CONTENT_LENGTH, new BasicHeader(HttpReqHead.CONTENT_LENGTH, contentLength)); return this; } /** * 请求的与实体对应的MIME信息 * 例如:Content-Type: application/x-www-form-urlencoded * * @param contentType */ public HttpHeader contentType(String contentType) { headerMaps.put(HttpReqHead.CONTENT_TYPE, new BasicHeader(HttpReqHead.CONTENT_TYPE, contentType)); return this; } /** * 请求发送的日期和时间 * 例如:Date: Tue, 15 Nov 2010 08:12:31 GMT * * @param date * @return */ public HttpHeader date(String date) { headerMaps.put(HttpReqHead.DATE, new BasicHeader(HttpReqHead.DATE, date)); return this; } /** * 请求的特定的服务器行为 * 例如:Expect: 100-continue * * @param expect */ public HttpHeader expect(String expect) { headerMaps.put(HttpReqHead.EXPECT, new BasicHeader(HttpReqHead.EXPECT, expect)); return this; } /** * 发出请求的用户的Email * 例如:From: user@email.com * * @param from */ public HttpHeader from(String from) { headerMaps.put(HttpReqHead.FROM, new BasicHeader(HttpReqHead.FROM, from)); return this; } /** * 指定请求的服务器的域名和端口号 * 例如:Host: blog.csdn.net * * @param host * @return */ public HttpHeader host(String host) { headerMaps.put(HttpReqHead.HOST, new BasicHeader(HttpReqHead.HOST, host)); return this; } /** * 只有请求内容与实体相匹配才有效 * 例如:If-Match: “737060cd8c284d8af7ad3082f209582d” * * @param ifMatch * @return */ public HttpHeader ifMatch(String ifMatch) { headerMaps.put(HttpReqHead.IF_MATCH, new BasicHeader(HttpReqHead.IF_MATCH, ifMatch)); return this; } /** * 如果请求的部分在指定时间之后被修改则请求成功,未被修改则返回304代码 * 例如:If-Modified-Since: Sat, 29 Oct 2010 19:43:31 GMT * * @param ifModifiedSince * @return */ public HttpHeader ifModifiedSince(String ifModifiedSince) { headerMaps.put(HttpReqHead.IF_MODIFIED_SINCE, new BasicHeader(HttpReqHead.IF_MODIFIED_SINCE, ifModifiedSince)); return this; } /** * 如果内容未改变返回304代码,参数为服务器先前发送的Etag,与服务器回应的Etag比较判断是否改变 * 例如:If-None-Match: “737060cd8c284d8af7ad3082f209582d” * * @param ifNoneMatch * @return */ public HttpHeader ifNoneMatch(String ifNoneMatch) { headerMaps.put(HttpReqHead.IF_NONE_MATCH, new BasicHeader(HttpReqHead.IF_NONE_MATCH, ifNoneMatch)); return this; } /** * 如果实体未改变,服务器发送客户端丢失的部分,否则发送整个实体。参数也为Etag * 例如:If-Range: “737060cd8c284d8af7ad3082f209582d” * * @param ifRange * @return */ public HttpHeader ifRange(String ifRange) { headerMaps.put(HttpReqHead.IF_RANGE, new BasicHeader(HttpReqHead.IF_RANGE, ifRange)); return this; } /** * 只在实体在指定时间之后未被修改才请求成功 * 例如:If-Unmodified-Since: Sat, 29 Oct 2010 19:43:31 GMT * * @param ifUnmodifiedSince * @return */ public HttpHeader ifUnmodifiedSince(String ifUnmodifiedSince) { headerMaps.put(HttpReqHead.IF_UNMODIFIED_SINCE, new BasicHeader(HttpReqHead.IF_UNMODIFIED_SINCE, ifUnmodifiedSince)); return this; } /** * 限制信息通过代理和网关传送的时间 * 例如:Max-Forwards: 10 * * @param maxForwards * @return */ public HttpHeader maxForwards(String maxForwards) { headerMaps.put(HttpReqHead.MAX_FORWARDS, new BasicHeader(HttpReqHead.MAX_FORWARDS, maxForwards)); return this; } /** * 用来包含实现特定的指令 * 例如:Pragma: no-cache * * @param pragma * @return */ public HttpHeader pragma(String pragma) { headerMaps.put(HttpReqHead.PRAGMA, new BasicHeader(HttpReqHead.PRAGMA, pragma)); return this; } /** * 连接到代理的授权证书 * 例如:Proxy-Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ== * * @param proxyAuthorization */ public HttpHeader proxyAuthorization(String proxyAuthorization) { headerMaps.put(HttpReqHead.PROXY_AUTHORIZATION, new BasicHeader(HttpReqHead.PROXY_AUTHORIZATION, proxyAuthorization)); return this; } /** * 只请求实体的一部分,指定范围 * 例如:Range: bytes=500-999 * * @param range */ public HttpHeader range(String range) { headerMaps.put(HttpReqHead.RANGE, new BasicHeader(HttpReqHead.RANGE, range)); return this; } /** * 先前网页的地址,当前请求网页紧随其后,即来路 * 例如:Referer: http://www.zcmhi.com/archives/71.html * * @param referer */ public HttpHeader referer(String referer) { headerMaps.put(HttpReqHead.REFERER, new BasicHeader(HttpReqHead.REFERER, referer)); return this; } /** * 客户端愿意接受的传输编码,并通知服务器接受接受尾加头信息 * 例如:TE: trailers,deflate;q=0.5 * * @param te */ public HttpHeader te(String te) { headerMaps.put(HttpReqHead.TE, new BasicHeader(HttpReqHead.TE, te)); return this; } /** * 向服务器指定某种传输协议以便服务器进行转换(如果支持) * 例如:Upgrade: HTTP/2.0, SHTTP/1.3, IRC/6.9, RTA/x11 * * @param upgrade */ public HttpHeader upgrade(String upgrade) { headerMaps.put(HttpReqHead.UPGRADE, new BasicHeader(HttpReqHead.UPGRADE, upgrade)); return this; } /** * User-Agent的内容包含发出请求的用户信息 * * @param userAgent * @return */ public HttpHeader userAgent(String userAgent) { headerMaps.put(HttpReqHead.USER_AGENT, new BasicHeader(HttpReqHead.USER_AGENT, userAgent)); return this; } /** * 关于消息实体的警告信息 * 例如:Warn: 199 Miscellaneous warning * * @param warning * @return */ public HttpHeader warning(String warning) { headerMaps.put(HttpReqHead.WARNING, new BasicHeader(HttpReqHead.WARNING, warning)); return this; } /** * 通知中间网关或代理服务器地址,通信协议 * 例如:Via: 1.0 fred, 1.1 nowhere.com (Apache/1.1) * * @param via * @return */ public HttpHeader via(String via) { headerMaps.put(HttpReqHead.VIA, new BasicHeader(HttpReqHead.VIA, via)); return this; } /** * 设置此HTTP连接的持续时间(超时时间) * 例如:Keep-Alive: 300 * * @param keepAlive * @return */ public HttpHeader keepAlive(String keepAlive) { headerMaps.put(HttpReqHead.KEEP_ALIVE, new BasicHeader(HttpReqHead.KEEP_ALIVE, keepAlive)); return this; } public String accept() { return get(HttpReqHead.ACCEPT); } public String acceptCharset() { return get(HttpReqHead.ACCEPT_CHARSET); } public String acceptEncoding() { return get(HttpReqHead.ACCEPT_ENCODING); } public String acceptLanguage() { return get(HttpReqHead.ACCEPT_LANGUAGE); } public String acceptRanges() { return get(HttpReqHead.ACCEPT_RANGES); } public String authorization() { return get(HttpReqHead.AUTHORIZATION); } public String cacheControl() { return get(HttpReqHead.CACHE_CONTROL); } public String connection() { return get(HttpReqHead.CONNECTION); } public String cookie() { return get(HttpReqHead.COOKIE); } public String contentLength() { return get(HttpReqHead.CONTENT_LENGTH); } public String contentType() { return get(HttpReqHead.CONTENT_TYPE); } public String date() { return get(HttpReqHead.DATE); } public String expect() { return get(HttpReqHead.EXPECT); } public String from() { return get(HttpReqHead.FROM); } public String host() { return get(HttpReqHead.HOST); } public String ifMatch() { return get(HttpReqHead.IF_MATCH); } public String ifModifiedSince() { return get(HttpReqHead.IF_MODIFIED_SINCE); } public String ifNoneMatch() { return get(HttpReqHead.IF_NONE_MATCH); } public String ifRange() { return get(HttpReqHead.IF_RANGE); } public String ifUnmodifiedSince() { return get(HttpReqHead.IF_UNMODIFIED_SINCE); } public String maxForwards() { return get(HttpReqHead.MAX_FORWARDS); } public String pragma() { return get(HttpReqHead.PRAGMA); } public String proxyAuthorization() { return get(HttpReqHead.PROXY_AUTHORIZATION); } public String referer() { return get(HttpReqHead.REFERER); } public String te() { return get(HttpReqHead.TE); } public String upgrade() { return get(HttpReqHead.UPGRADE); } public String userAgent() { return get(HttpReqHead.USER_AGENT); } public String via() { return get(HttpReqHead.VIA); } public String warning() { return get(HttpReqHead.WARNING); } public String keepAlive() { return get(HttpReqHead.KEEP_ALIVE); } /** * 获取head信息 * * @return */ private String get(String headName) { if (headerMaps.containsKey(headName)) { return headerMaps.get(headName).getValue(); } return null; } /** * 返回header头信息 * * @return */ public Header[] build() { Header[] headers = new Header[headerMaps.size()]; int i = 0; for (Header header : headerMaps.values()) { headers[i] = header; i++; } headerMaps.clear(); headerMaps = null; return headers; } /** * Http头信息 * * @author arron * @date 2015年11月9日 上午11:29:04 * @version 1.0 */ private static class HttpReqHead { public static final String ACCEPT = "Accept"; public static final String ACCEPT_CHARSET = "Accept-Charset"; public static final String ACCEPT_ENCODING = "Accept-Encoding"; public static final String ACCEPT_LANGUAGE = "Accept-Language"; public static final String ACCEPT_RANGES = "Accept-Ranges"; public static final String AUTHORIZATION = "Authorization"; public static final String CACHE_CONTROL = "Cache-Control"; public static final String CONNECTION = "Connection"; public static final String COOKIE = "Cookie"; public static final String CONTENT_LENGTH = "Content-Length"; public static final String CONTENT_TYPE = "Content-Type"; public static final String DATE= "Date"; public static final String EXPECT = "Expect"; public static final String FROM = "From"; public static final String HOST = "Host"; public static final String IF_MATCH = "If-Match "; public static final String IF_MODIFIED_SINCE = "If-Modified-Since"; public static final String IF_NONE_MATCH = "If-None-Match"; public static final String IF_RANGE = "If-Range"; public static final String IF_UNMODIFIED_SINCE = "If-Unmodified-Since"; public static final String KEEP_ALIVE = "Keep-Alive"; public static final String MAX_FORWARDS = "Max-Forwards"; public static final String PRAGMA = "Pragma"; public static final String PROXY_AUTHORIZATION = "Proxy-Authorization"; public static final String RANGE = "Range"; public static final String REFERER = "Referer"; public static final String TE = "TE"; public static final String UPGRADE = "Upgrade"; public static final String USER_AGENT = "User-Agent"; public static final String VIA = "Via"; public static final String WARNING = "Warning"; } /** * 常用头信息配置 * * @author arron * @date 2015年11月18日 下午5:30:00 * @version 1.0 */ public static class Headers{ public static final String APP_FORM_URLENCODED="application/x-www-form-urlencoded"; public static final String TEXT_PLAIN="text/plain"; public static final String TEXT_HTML="text/html"; public static final String TEXT_XML="text/xml"; public static final String TEXT_JSON="text/json"; public static final String CONTENT_CHARSET_ISO_8859_1 = Consts.ISO_8859_1.name(); public static final String CONTENT_CHARSET_UTF8 = Consts.UTF_8.name(); public static final String DEF_PROTOCOL_CHARSET = Consts.ASCII.name(); public static final String CONN_CLOSE = "close"; public static final String KEEP_ALIVE = "keep-alive"; public static final String EXPECT_CONTINUE = "100-continue"; } } ~~~      调用方式: ~~~ //设置header信息 Header[] headers=HttpHeader.custom().keepAlive("false").connection("close").contentType(Headers.APP_FORM_URLENCODED).build(); ~~~      就是这么简单。到此该工具类就完成了。下一篇将分享该工具类以及单次调用测试和多线程调用测试。      代码已上传至:[https://github.com/Arronlong/httpclientUtil](https://github.com/Arronlong/httpclientUtil)。
';

轻松把玩HttpClient之封装HttpClient工具类(二),插件式配置HttpClient对象

最后更新于:2022-04-01 22:59:55

     版权声明:本文为博主原创文章,未经博主允许不得转载。如需转载请声明:【转自 http://blog.csdn.net/xiaoxian8023 】      上一篇文章中,简单分享一下封装HttpClient工具类的思路及部分代码,本文将分享如何实现插件式配置HttpClient对象。      如果你看过我前面的几篇关于HttpClient的文章或者官网示例,应该都知道HttpClient对象在创建时,都可以设置各种参数,但是却没有简单的进行封装,比如对我来说比较重要的3个:代理、ssl(包含绕过证书验证和自定义证书验证)、超时。还需要自己写。所以这里我就简单封装了一下,顺便还封装了一个连接池的配置。      其实说是插件式配置,那是高大上的说法,说白了,就是采用了建造者模式来创建HttpClient对象(级联调用)。HttpClient的jar包中提供了一个创建HttpClient对象的类HttpClientBuilder。所以我是创建该类的子类HCB,然后做了一些改动。每个配置方法的返回值都是HCB,这样就支持级联调用了。具体代码如下: ~~~ package com.tgb.ccl.http.httpclient.builder; import org.apache.http.HttpHost; import org.apache.http.client.config.RequestConfig; import org.apache.http.config.Registry; import org.apache.http.config.RegistryBuilder; import org.apache.http.conn.socket.ConnectionSocketFactory; import org.apache.http.conn.socket.PlainConnectionSocketFactory; import org.apache.http.impl.client.HttpClientBuilder; import org.apache.http.impl.conn.DefaultProxyRoutePlanner; import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; import com.tgb.ccl.http.common.SSLs; import com.tgb.ccl.http.exception.HttpProcessException; /** * httpclient创建者 * * @author arron * @date 2015年11月9日 下午5:45:47 * @version 1.0 */ public class HCB extends HttpClientBuilder{ private boolean isSetPool=false;//记录是否设置了连接池 private boolean isNewSSL=false;//记录是否设置了更新了ssl //用于配置ssl private SSLs ssls = SSLs.getInstance(); private HCB(){} public static HCB custom(){ return new HCB(); } /** * 设置超时时间 * * @param timeout 超市时间,单位-毫秒 * @return */ public HCB timeout(int timeout){ // 配置请求的超时设置 RequestConfig config = RequestConfig.custom() .setConnectionRequestTimeout(timeout) .setConnectTimeout(timeout) .setSocketTimeout(timeout) .build(); return (HCB) this.setDefaultRequestConfig(config); } /** * 设置ssl安全链接 * * @return * @throws HttpProcessException */ public HCB ssl() throws HttpProcessException { if(isSetPool){//如果已经设置过线程池,那肯定也就是https链接了 if(isNewSSL){ throw new HttpProcessException("请先设置ssl,后设置pool"); } return this; } Registry socketFactoryRegistry = RegistryBuilder . create() .register("http", PlainConnectionSocketFactory.INSTANCE) .register("https", ssls.getSSLCONNSF()).build(); //设置连接池大小 PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry); return (HCB) this.setConnectionManager(connManager); } /** * 设置自定义sslcontext * * @param keyStorePath 密钥库路径 * @return * @throws HttpProcessException */ public HCB ssl(String keyStorePath) throws HttpProcessException{ return ssl(keyStorePath,"nopassword"); } /** * 设置自定义sslcontext * * @param keyStorePath 密钥库路径 * @param keyStorepass 密钥库密码 * @return * @throws HttpProcessException */ public HCB ssl(String keyStorePath, String keyStorepass) throws HttpProcessException{ this.ssls = SSLs.custom().customSSL(keyStorePath, keyStorepass); this.isNewSSL=true; return ssl(); } /** * 设置连接池(默认开启https) * * @param maxTotal 最大连接数 * @param defaultMaxPerRoute 每个路由默认连接数 * @return * @throws HttpProcessException */ public HCB pool(int maxTotal, int defaultMaxPerRoute) throws HttpProcessException{ Registry socketFactoryRegistry = RegistryBuilder . create() .register("http", PlainConnectionSocketFactory.INSTANCE) .register("https", ssls.getSSLCONNSF()).build(); //设置连接池大小 PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry); connManager.setMaxTotal(maxTotal); connManager.setDefaultMaxPerRoute(defaultMaxPerRoute); isSetPool=true; return (HCB) this.setConnectionManager(connManager); } /** * 设置代理 * * @param hostOrIP 代理host或者ip * @param port 代理端口 * @return */ public HCB proxy(String hostOrIP, int port){ // 依次是代理地址,代理端口号,协议类型 HttpHost proxy = new HttpHost(hostOrIP, port, "http"); DefaultProxyRoutePlanner routePlanner = new DefaultProxyRoutePlanner(proxy); return (HCB) this.setRoutePlanner(routePlanner); } } ~~~      大家可以看到,这个有成员变量,而且不是static类型,所以是非线程安全的。所以我为了方便使用,就效仿HttpClients(其custom方法可以创建HttpClientBuilder实例)写了一个静态的custom方法,来返回一个新的HCB实例。将构造方法设置成了private,无法通过new的方式创建实例,所以只能通过custom方法来创建。在想生成HttpClient对象的时候,调用一下build方法就可以了。于是乎就出现了这样简单、方便又明了的调用方式: ~~~ HttpClient client = HCB.custom().timeout(10000).proxy("127.0.0.1", 8087).ssl("D:\\keys\\wsriakey","tomcat").build(); ~~~      说到ssl,还需要另外一个封装的类,为了其他工具类有可能也会用到ssl,所以就单出来了。不多解释,直接上代码: ~~~ /** * 设置ssl * * @author arron * @date 2015年11月3日 下午3:11:54 * @version 1.0 */ public class SSLs { private static final SSLHandler simpleVerifier = new SSLHandler(); private static SSLConnectionSocketFactory sslConnFactory ; private static SSLs sslutil = new SSLs(); private SSLContext sc; public static SSLs getInstance(){ return sslutil; } public static SSLs custom(){ return new SSLs(); } // 重写X509TrustManager类的三个方法,信任服务器证书 private static class SSLHandler implements X509TrustManager, HostnameVerifier{ @Override public java.security.cert.X509Certificate[] getAcceptedIssuers() { return null; } @Override public void checkServerTrusted(java.security.cert.X509Certificate[] chain, String authType) throws java.security.cert.CertificateException { } @Override public void checkClientTrusted(java.security.cert.X509Certificate[] chain, String authType) throws java.security.cert.CertificateException { } @Override public boolean verify(String paramString, SSLSession paramSSLSession) { return true; } }; // 信任主机 public static HostnameVerifier getVerifier() { return simpleVerifier; } public synchronized SSLConnectionSocketFactory getSSLCONNSF() throws HttpProcessException { if (sslConnFactory != null) return sslConnFactory; try { SSLContext sc = getSSLContext(); sc.init(null, new TrustManager[] { simpleVerifier }, null); sslConnFactory = new SSLConnectionSocketFactory(sc, simpleVerifier); } catch (KeyManagementException e) { throw new HttpProcessException(e); } return sslConnFactory; } public SSLs customSSL(String keyStorePath, String keyStorepass) throws HttpProcessException{ FileInputStream instream =null; KeyStore trustStore = null; try { trustStore = KeyStore.getInstance(KeyStore.getDefaultType()); instream = new FileInputStream(new File(keyStorePath)); trustStore.load(instream, keyStorepass.toCharArray()); // 相信自己的CA和所有自签名的证书 sc= SSLContexts.custom().loadTrustMaterial(trustStore, new TrustSelfSignedStrategy()) .build(); } catch (KeyStoreException | NoSuchAlgorithmException | CertificateException | IOException | KeyManagementException e) { throw new HttpProcessException(e); }finally{ try { instream.close(); } catch (IOException e) {} } return this; } public SSLContext getSSLContext() throws HttpProcessException{ try { if(sc==null){ sc = SSLContext.getInstance("SSLv3"); } return sc; } catch (NoSuchAlgorithmException e) { throw new HttpProcessException(e); } } } ~~~      基本上就是这样了。在上一篇中遗留了一个小问题,正好在这里说一下。上一篇文中说道提供一个默认的HttpClient实现,其实是2个,分别针对于http和https。方便调用。具体代码如下: ~~~ //默认采用的http协议的HttpClient对象 private static HttpClient client4HTTP; //默认采用的https协议的HttpClient对象 private static HttpClient client4HTTPS; static{ try { client4HTTP = HCB.custom().build(); client4HTTPS = HCB.custom().ssl().build(); } catch (HttpProcessException e) { logger.error("创建https协议的HttpClient对象出错:{}", e); } } /** * 判断url是http还是https,直接返回相应的默认client对象 * * @return 返回对应默认的client对象 * @throws HttpProcessException */ private static HttpClient create(String url) throws HttpProcessException { if(url.toLowerCase().startsWith("https://")){ return client4HTTPS; }else{ return client4HTTP; } } ~~~      这样在使用工具类的时候,如果不需要自定义HttpClient时,就直接用下面的方式调用: ~~~ public static void testSimple() throws HttpProcessException{ String url = "http://tool.oschina.net/"; //简单调用 String resp = HttpClientUtil.send(url); System.out.println("请求结果内容长度:"+ resp); } ~~~      好了,插件化配置HttpClient,就是这些内容,在下一篇文章中分享如何插件式配置Header。没错,思路还是跟本文一样。敬请期待吧。      代码已上传至:[https://github.com/Arronlong/httpclientUtil](https://github.com/Arronlong/httpclientUtil)。
';

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

最后更新于:2022-04-01 22:59:53

     版权声明:本文为博主原创文章,未经博主允许不得转载。如需转载请声明:【转自 http://blog.csdn.net/xiaoxian8023 】      搜了一下网络上别人封装的HttpClient,大部分特别简单,有一些看起来比较高级,但是用起来都不怎么好用。调用关系不清楚,结构有点混乱。所以也就萌生了自己封装HttpClient工具类的想法。要做就做最好的,本工具类支持插件式配置Header、插件式配置httpclient对象,这样就可以方便地自定义header信息、配置ssl、配置proxy等。      是不是觉得说的有点悬乎了,那就先看看调用吧: ~~~ public static void testSimple() throws HttpProcessException{ String url = "http://www.oschina.net"; //简单调用 String resp = HttpClientUtil.send(url); System.out.println("请求结果内容长度:"+ resp.length()); } public static void testOne() throws HttpProcessException{ String url = "https://sso.tgb.com:8443/cas/login"; //自定义HttpClient,设置超时、代理、ssl //HttpClient client= HCB.custom().timeout(10000).proxy("127.0.0.1", 8087).ssl().build();//采用默认方式(绕过证书验证) HttpClient client= HCB.custom().timeout(10000).ssl("D:\\keys\\wsriakey","tomcat").build(); //设置header信息 Header[] headers=HttpHeader.custom().keepAlive("false").connection("close").contentType(Headers.APP_FORM_URLENCODED).build(); //执行请求 String resp=HttpClientUtil.send(client, url, headers); System.out.println("请求结果如下:"); System.out.println(resp); } ~~~      轻松配置了代理、自定义证书的ssl、以及各种header头信息,是不是觉得还凑合呢,那就继续看吧。      写这个工具类时,抽象了一下所有的demo,最后封装了一个最基本的方法(拆分成了2个方法了),其所有参数列表有:HttpClient对象、url(必须有)、请求方式、请求参数parasMap、header数组、编码格式encoding。      由于封装的是工具类,所以最好是无状态的,可以支持多线程的方式调用的,所以方法都是static类型的。这也是为什么要把HttpClient对象也是作为了一个参数传入而非成员变量了,而且这样也为扩展HttpClient的配置提供了便利。      因为HTTP1.1规范中定义了6种HTTP方法:GET, HEAD, POST, PUT, DELETE, TRACE 和 OPTIONS,其实还有一个PATCH,这几个方法在HttpClient中都有一个对应的类:HttpGet,HttpHead,HttpPost,HttpPut,HttpDelete,HttpTrace、HttpOptions以及HttpPatch。所有的这些类均继承了HttpRequestBase超类,故可以作为参数使用(用枚举类作为参数,用另一个方法来创建具体的请求方法对象)。      Header头信息也是作为一个重要的参数,在请求特定网站的时候需要设置不同的Header,而header又是比较繁杂的,所以这里也是作为了一个参数传入的,也是方便扩展。      使用map来作为post方式传入参数是习惯使然,不做过多的解释。      编码这个参数主要是为了为待提交的数据和反馈结果进行转码处理。      简单说一下流程: 1. 创建请求对象request; 2. 为request设置header信息; 3. 判断当前请求对象是否是HttpEntityEnclosingRequestBase的子类,如果是,则支持setEntity方法,来设置参数。 4. 执行请求,并拿到结果(同步阻塞); 5. 获取并解码请求结果实体; 6. 关闭链接      就是这么简单,具体来看看代码吧: ~~~ /** * 请求资源或服务,自定义client对象,传入请求参数,设置内容类型,并指定参数和返回数据的编码 * * @param client client对象 * @param url 资源地址 * @param httpMethod 请求方法 * @param parasMap 请求参数 * @param headers 请求头信息 * @param encoding 编码 * @return 返回处理结果 * @throws HttpProcessException */ public static String send(HttpClient client, String url, HttpMethods httpMethod, MapparasMap,  Header[] headers, String encoding) throws HttpProcessException { String body = ""; try { //创建请求对象 HttpRequestBase request = getRequest(url, httpMethod); //设置header信息 request.setHeaders(headers); //判断是否支持设置entity(仅HttpPost、HttpPut、HttpPatch支持) if(HttpEntityEnclosingRequestBase.class.isAssignableFrom(request.getClass())){ List nvps = new ArrayList(); //检测url中是否存在参数 url = Utils.checkHasParas(url, nvps); //装填参数 Utils.map2List(nvps, parasMap); //设置参数到请求对象中 ((HttpEntityEnclosingRequestBase)request).setEntity(new UrlEncodedFormEntity(nvps, encoding)); logger.debug("请求地址:"+url); if(nvps.size()>0){ logger.debug("请求参数:"+nvps.toString()); } }else{ int idx = url.indexOf("?"); logger.debug("请求地址:"+url.substring(0, (idx>0 ? idx-1:url.length()-1))); if(idx>0){ logger.debug("请求参数:"+url.substring(idx+1)); } } //调用发送请求 body = execute(client, request, url, encoding); } catch (UnsupportedEncodingException e) { throw new HttpProcessException(e); } return body; } /** * 请求资源或服务 * * @param client client对象 * @param request 请求对象 * @param url 资源地址 * @param parasMap 请求参数 * @param encoding 编码 * @return 返回处理结果 * @throws HttpProcessException */ private static String execute(HttpClient client, HttpRequestBase request,String url, String encoding) throws HttpProcessException { String body = ""; HttpResponse response =null; try { //执行请求操作,并拿到结果(同步阻塞) response = client.execute(request); //获取结果实体 HttpEntity entity = response.getEntity(); if (entity != null) { //按指定编码转换结果实体为String类型 body = EntityUtils.toString(entity, encoding); logger.debug(body); } EntityUtils.consume(entity); } catch (ParseException | IOException e) { throw new HttpProcessException(e); } finally { close(response); } return body; } ~~~      第一个方法中,我们看到有HttpMethods类型的参数,在创建request对象时,用到了它。它是什么呢?其实只是一个枚举类: ~~~ /** * 枚举HttpMethods方法 * * @author arron * @date 2015年11月17日 下午4:45:59 * @version 1.0 */ public enum HttpMethods{ /** * 求获取Request-URI所标识的资源 */ GET(0, "GET"), /** * 向指定资源提交数据进行处理请求(例如提交表单或者上传文件)。数据被包含在请求体中。 * POST请求可能会导致新的资源的建立和/或已有资源的修改 */ POST(1, "POST"), /** * 向服务器索要与GET请求相一致的响应,只不过响应体将不会被返回。 * 这一方法可以在不必传输整个响应内容的情况下,就可以获取包含在响应消息头中的元信息 * 只获取响应信息报头 */ HEAD(2, "HEAD"), /** * 向指定资源位置上传其最新内容(全部更新,操作幂等) */ PUT (3, "PUT"), /** * 请求服务器删除Request-URI所标识的资源 */ DELETE (4, "DELETE"), /** * 请求服务器回送收到的请求信息,主要用于测试或诊断 */ TRACE(5, "TRACE"), /** * 向指定资源位置上传其最新内容(部分更新,非幂等) */ PATCH (6, "PATCH"), /** * 返回服务器针对特定资源所支持的HTTP请求方法。 * 也可以利用向Web服务器发送'*'的请求来测试服务器的功能性 */ OPTIONS (7, "OPTIONS"), // /** // * HTTP/1.1协议中预留给能够将连接改为管道方式的代理服务器 // */ // CONNECT(99, "CONNECT"), ; private int code; private String name; private HttpMethods(int code, String name){ this.code = code; this.name = name; } public String getName() { return name; } public int getCode() { return code; } } ~~~      通过getRequest方法,来实例化对应方法的请求对象。 ~~~ /** * 根据请求方法名,获取request对象 * * @param url 资源地址 * @param method 请求方式 * @return */ private static HttpRequestBase getRequest(String url, HttpMethods method) { HttpRequestBase request = null; switch (method.getCode()) { case 0:// HttpGet request = new HttpGet(url); break; case 1:// HttpPost request = new HttpPost(url); break; case 2:// HttpHead request = new HttpHead(url); break; case 3:// HttpPut request = new HttpPut(url); break; case 4:// HttpDelete request = new HttpDelete(url); break; case 5:// HttpTrace request = new HttpTrace(url); break; case 6:// HttpPatch request = new HttpPatch(url); break; case 7:// HttpOptions request = new HttpOptions(url); break; default: request = new HttpPost(url); break; } return request; } ~~~      当然最后的关闭链接也是一个小方法: ~~~ /** * 尝试关闭response * * @param resp HttpResponse对象 */ private static void close(HttpResponse resp) { try { if(resp == null) return; //如果CloseableHttpResponse 是resp的父类,则支持关闭 if(CloseableHttpResponse.class.isAssignableFrom(resp.getClass())){ ((CloseableHttpResponse)resp).close(); } } catch (IOException e) { logger.error(e); } } ~~~      当然各种参数的组合方法也简单提供一下(为了节约空间,已去掉注释): ~~~ public static String send(String url) throws HttpProcessException { return send(url, Charset.defaultCharset().name()); } public static String send(String url, String encoding) throws HttpProcessException { return send(url, new Header[]{},encoding); } public static String send(String url, Header[] headers) throws HttpProcessException { return send(url, headers, Charset.defaultCharset().name()); } public static String send(String url, Header[] headers, String encoding) throws HttpProcessException { return send(url, new HashMap(), headers, encoding); } public static String send(String url, MapparasMap) throws HttpProcessException { return send(url, parasMap, Charset.defaultCharset().name()); } public static String send(String url, MapparasMap, String encoding) throws HttpProcessException { return send(url, parasMap, new Header[]{}, encoding); } public static String send(String url, MapparasMap, Header[] headers) throws HttpProcessException { return send(url, parasMap, headers, Charset.defaultCharset().name()); } public static String send(String url, MapparasMap, Header[] headers, String encoding) throws HttpProcessException { return send(url, HttpMethods.POST, parasMap, headers, encoding); } public static String send(String url, HttpMethods httpMethod) throws HttpProcessException { return send(url, httpMethod, Charset.defaultCharset().name()); } public static String send(String url, HttpMethods httpMethod, String encoding) throws HttpProcessException { return send(url, httpMethod, new Header[]{},encoding); } public static String send(String url, HttpMethods httpMethod, Header[] headers) throws HttpProcessException { return send(url, httpMethod, headers, Charset.defaultCharset().name()); } public static String send(String url, HttpMethods httpMethod, Header[] headers, String encoding) throws HttpProcessException { return send(url, httpMethod, new HashMap(), headers, encoding); } public static String send(String url, HttpMethods httpMethod, MapparasMap) throws HttpProcessException { return send(url, httpMethod, parasMap, Charset.defaultCharset().name()); } public static String send(String url, HttpMethods httpMethod, MapparasMap, String encoding) throws HttpProcessException { return send(url, httpMethod, parasMap, new Header[]{}, encoding); } public static String send(String url, HttpMethods httpMethod, MapparasMap, Header[] headers) throws HttpProcessException { return send(url, httpMethod, parasMap, headers, Charset.defaultCharset().name()); } public static String send(String url, HttpMethods httpMethod, MapparasMap, Header[] headers, String encoding) throws HttpProcessException { return send(create(url), url, httpMethod, parasMap, headers, encoding); } public static String send(HttpClient client, String url) throws HttpProcessException { return send(client, url, Charset.defaultCharset().name()); } public static String send(HttpClient client, String url, String encoding) throws HttpProcessException { return send(client, url, new Header[]{}, encoding); } public static String send(HttpClient client, String url, Header[] headers) throws HttpProcessException { return send(client, url, headers, Charset.defaultCharset().name()); } public static String send(HttpClient client, String url, Header[] headers, String encoding) throws HttpProcessException { return send(client, url, new HashMap(), headers, encoding); } public static String send(HttpClient client, String url, MapparasMap) throws HttpProcessException { return send(client, url, parasMap, Charset.defaultCharset().name()); } public static String send(HttpClient client, String url, MapparasMap, String encoding) throws HttpProcessException { return send(client, url, parasMap, new Header[]{}, encoding); } public static String send(HttpClient client, String url, MapparasMap, Header[] headers) throws HttpProcessException { return send(client, url, parasMap, headers, Charset.defaultCharset().name()); } public static String send(HttpClient client, String url, MapparasMap,Header[] headers,String encoding) throws HttpProcessException { return send(client, url, HttpMethods.POST, parasMap, headers, encoding); } public static String send(HttpClient client, String url, HttpMethods httpMethod) throws HttpProcessException { return send(client, url, httpMethod, Charset.defaultCharset().name()); } public static String send(HttpClient client, String url, HttpMethods httpMethod, String encoding) throws HttpProcessException { return send(client, url, httpMethod, new Header[]{}, encoding); } public static String send(HttpClient client, String url, HttpMethods httpMethod, Header[] headers) throws HttpProcessException { return send(client, url, httpMethod, headers, Charset.defaultCharset().name()); } public static String send(HttpClient client, String url, HttpMethods httpMethod, Header[] headers, String encoding) throws HttpProcessException { return send(client, url, httpMethod, new HashMap(), headers, encoding); } public static String send(HttpClient client, String url, HttpMethods httpMethod, MapparasMap) throws HttpProcessException { return send(client, url, httpMethod, parasMap, Charset.defaultCharset().name()); } public static String send(HttpClient client, String url, HttpMethods httpMethod, MapparasMap, String encoding) throws HttpProcessException { return send(client, url, httpMethod, parasMap, new Header[]{}, encoding); } public static String send(HttpClient client, String url, HttpMethods httpMethod, MapparasMap, Header[] headers) throws HttpProcessException { return send(client, url, httpMethod, parasMap, headers, Charset.defaultCharset().name()); } ~~~      可以看到上面这一堆方法,其实主要分成2类,一类是传入client对象的,一组是没有传入的。也就是说该工具类提供了一种默认的client对象。这个将会在下一篇文章会有补充。      当然,为了方便操作,还是提供了get、post、put、patch、delete、head、options、trace等方法,由于推荐使用send方法,所以这几个方法只是做了一个简单的调用: ~~~ public static String get(String url, Header[] headers,String encoding) throws HttpProcessException { return get(create(url), url, headers, encoding); } public static String get(HttpClient client, String url, Header[] headers,String encoding) throws HttpProcessException { return send(client, url, HttpMethods.GET, headers, encoding); } public static String post(String url, MapparasMap,Header[] headers,String encoding) throws HttpProcessException { return post(create(url), url, parasMap, headers, encoding); } public static String post(HttpClient client, String url, MapparasMap,Header[] headers,String encoding) throws HttpProcessException { return send(client, url, HttpMethods.POST, parasMap, headers, encoding); } public static String put(String url, MapparasMap,Header[] headers,String encoding) throws HttpProcessException { return put(create(url), url, parasMap, headers, encoding); } public static String put(HttpClient client, String url, MapparasMap,Header[] headers,String encoding) throws HttpProcessException { return send(client, url, HttpMethods.PUT, parasMap, headers, encoding); } public static String delete(String url, Header[] headers,String encoding) throws HttpProcessException { return delete(create(url), url, headers, encoding); } public static String delete(HttpClient client, String url, Header[] headers,String encoding) throws HttpProcessException { return send(client, url, HttpMethods.DELETE, headers, encoding); } public static String patch(String url, MapparasMap,Header[] headers,String encoding) throws HttpProcessException { return patch(create(url), url, parasMap, headers, encoding); } public static String patch(HttpClient client, String url, MapparasMap, Header[] headers,String encoding) throws HttpProcessException { return send(client, url, HttpMethods.PATCH, parasMap, headers, encoding); } public static String head(String url, Header[] headers,String encoding) throws HttpProcessException { return head(create(url), url, headers, encoding); } public static String head(HttpClient client, String url, Header[] headers,String encoding) throws HttpProcessException { return send(client, url, HttpMethods.HEAD, headers, encoding); } public static String options(String url, Header[] headers,String encoding) throws HttpProcessException { return options(create(url), url, headers, encoding); } public static String options(HttpClient client, String url, Header[] headers,String encoding) throws HttpProcessException { return send(client, url, HttpMethods.OPTIONS, headers, encoding); } public static String trace(String url, Header[] headers,String encoding) throws HttpProcessException { return trace(create(url), url, headers, encoding); } public static String trace(HttpClient client, String url, Header[] headers,String encoding) throws HttpProcessException { return send(client, url, HttpMethods.TRACE, headers, encoding); } ~~~      差点忘记了,最后还有一个简单的通用工具类 ~~~ /** * * @author arron * @date 2015年11月10日 下午12:49:26 * @version 1.0 */ public class Utils { /** * 检测url是否含有参数,如果有,则把参数加到参数列表中 * * @param url 资源地址 * @param nvps 参数列表 * @return 返回去掉参数的url */ public static String checkHasParas(String url, List nvps) { // 检测url中是否存在参数 if (url.contains("?") && url.indexOf("?") < url.indexOf("=")) { Map map = buildParas(url.substring(url .indexOf("?") + 1)); map2List(nvps, map); url = url.substring(0, url.indexOf("?")); } return url; } /** * 参数转换,将map中的参数,转到参数列表中 * * @param nvps 参数列表 * @param map 参数列表(map) */ public static void map2List(List nvps, Map map) { if(map==null) return; // 拼接参数 for (Entry entry : map.entrySet()) { nvps.add(new BasicNameValuePair(entry.getKey(), entry .getValue())); } } /** * 生成参数 * 参数格式“k1=v1&k2=v2” * * @param paras 参数列表 * @return 返回参数列表(map) */ public static Map buildParas(String paras){ String[] p = paras.split("&"); String[][] ps = new String[p.length][2]; int pos = 0; for (int i = 0; i < p.length; i++) { pos = p[i].indexOf("="); ps[i][0]=p[i].substring(0,pos); ps[i][1]=p[i].substring(pos+1); pos = 0; } return buildParas(ps); } /** * 生成参数 * 参数类型:{{"k1","v1"},{"k2","v2"}} * * @param paras 参数列表 * @return 返回参数列表(map) */ public static Map buildParas(String[][] paras){ // 创建参数队列 Map map = new HashMap(); for (String[] para: paras) { map.put(para[0], para[1]); } return map; } } ~~~      简单的封装就是这样了。      由于HttpClient和Header都作为参数传入,所以也可以进行扩展,比如代理、ssl等都是对HttpClient进行配置的,下面的文章就分别分享一下如何插件式配置HttpClient以及Header。敬请期待。      代码已上传至:[https://github.com/Arronlong/httpclientUtil](https://github.com/Arronlong/httpclientUtil)。
';

轻松把玩HttpClient之设置代理,可以访问FaceBook

最后更新于:2022-04-01 22:59:50

     版权声明:本文为博主原创文章,未经博主允许不得转载。如需转载请声明:【转自 http://blog.csdn.net/xiaoxian8023 】      前面的文章介绍了一些HttpClient的简单示例,本文继续采用示例的方式来演示HttpClient的功能。      在项目中我们可能会遇到这样的情况:为了保证系统的安全性,只允许使用特定的代理才可以访问,而与这些系统使用HttpClient进行交互时,只能为其配置代理。      这里我们使用goagent代理访问脸书来模拟这种情况。facebook由于某些原因被封,只能通过代理来访问,所以正好也符合我们现在的演示需求。现在在浏览器上访问是可以访问的: ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-02-18_56c53cb7c41ee.jpg)      可以看到facebook采用的也是https的方式,而且该网站的证书不客户端被信任。所以我们要采用“绕过证书验证”的方式使用Https。那如何设置代理呢,官网有[相关的示例](http://hc.apache.org/httpcomponents-client-4.5.x/httpclient/examples/org/apache/http/examples/client/ClientExecuteProxy.java)。我采用的跟官网提供的稍微不一样,具体代码如下: ~~~ /** * 设置代理 * @param builder * @param hostOrIP * @param port */ public static HttpClientBuilder proxy(String hostOrIP, int port){ // 依次是代理地址,代理端口号,协议类型 HttpHost proxy = new HttpHost(hostOrIP, port, "http"); DefaultProxyRoutePlanner routePlanner = new DefaultProxyRoutePlanner(proxy); return HttpClients.custom().setRoutePlanner(routePlanner); } ~~~      返回值是HttpClientBuilder,这个类是用来生成HttpClient对象的,同时可以设置各种参数,这里提供返回值是为了配置代理后,继续配置ssl。打开goagent,看看代理ip的设定如图: ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-02-18_56c53cb7e21ef.jpg)      现在修改send方法: ~~~ /** * 模拟请求 * * @param url 资源地址 * @param map 参数列表 * @param encoding 编码 * @return * @throws NoSuchAlgorithmException * @throws KeyManagementException * @throws IOException * @throws ClientProtocolException */ public static String send(String url, Map map,String encoding) throws KeyManagementException, NoSuchAlgorithmException, ClientProtocolException, IOException { String body = ""; //绕过证书验证,处理https请求 SSLContext sslcontext = createIgnoreVerifySSL(); // 设置协议http和https对应的处理socket链接工厂的对象 Registry socketFactoryRegistry = RegistryBuilder.create() .register("http", PlainConnectionSocketFactory.INSTANCE) .register("https", new SSLConnectionSocketFactory(sslcontext)) .build(); PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry); HttpClients.custom().setConnectionManager(connManager); //创建自定义的httpclient对象 CloseableHttpClient client = proxy("127.0.0.1", 8087).setConnectionManager(connManager).build(); // CloseableHttpClient client = HttpClients.createDefault(); //创建post方式请求对象 HttpPost httpPost = new HttpPost(url); //装填参数 List nvps = new ArrayList(); if(map!=null){ for (Entry entry : map.entrySet()) { nvps.add(new BasicNameValuePair(entry.getKey(), entry.getValue())); } } //设置参数到请求对象中 httpPost.setEntity(new UrlEncodedFormEntity(nvps, encoding)); System.out.println("请求地址:"+url); System.out.println("请求参数:"+nvps.toString()); //设置header信息 //指定报文头【Content-type】、【User-Agent】 httpPost.setHeader("Content-type", "application/x-www-form-urlencoded"); httpPost.setHeader("User-Agent", "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt)"); //执行请求操作,并拿到结果(同步阻塞) CloseableHttpResponse response = client.execute(httpPost); //获取结果实体 HttpEntity entity = response.getEntity(); if (entity != null) { //按指定编码转换结果实体为String类型 body = EntityUtils.toString(entity, encoding); } EntityUtils.consume(entity); //释放链接 response.close(); return body; } ~~~      测试代码如下: ~~~ public static void main(String[] args) throws ParseException, IOException, KeyManagementException, NoSuchAlgorithmException{ String url = "https://www.facebook.com/"; String body = send(url, null, "utf-8"); System.out.println("交易响应结果"); System.out.println(body); } ~~~      运行后,结果: ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-02-18_56c53cb802de8.jpg)      果然可以访问成功了。      好了基本的教程就到这里,下篇我将其封装的一个工具类,自认为相对于网上分享的封装类要强大很多,敬请期待吧。
';

轻松把玩HttpClient之配置ssl,采用设置信任自签名证书实现https

最后更新于:2022-04-01 22:59:48

     版权声明:本文为博主原创文章,未经博主允许不得转载。如需转载请声明:【转自 http://blog.csdn.net/xiaoxian8023 】      在上篇文章《[HttpClient配置ssl实现https简单示例——绕过证书验证](http://blog.csdn.net/xiaoxian8023/article/details/49865335)》中简单分享了一下如何绕过证书验证。如果你想用httpclient访问一个网站,但是对方的证书没有通过ca认证或者其他问题导致证书不被信任,比如12306的证书就是这样的。所以对于这样的情况,你只能是选择绕过证书验证的方案了。      但是,如果是自己用jdk或者其他工具生成的证书,还是希望用其他方式认证自签名的证书,这篇文章就来分享一下如何设置信任自签名的证书。当然你也可以参考[官网示例](http://hc.apache.org/httpcomponents-client-4.5.x/httpclient/examples/org/apache/http/examples/client/ClientCustomSSL.java)中。      要想信任自签名的证书,必须得知道密钥库的路径及密钥库的密码。然后加载到程序来才可以。具体代码如下: ~~~ /** * 设置信任自签名证书 * * @param keyStorePath 密钥库路径 * @param keyStorepass 密钥库密码 * @return */ public static SSLContext custom(String keyStorePath, String keyStorepass){ SSLContext sc = null; FileInputStream instream = null; KeyStore trustStore = null; try { trustStore = KeyStore.getInstance(KeyStore.getDefaultType()); instream = new FileInputStream(new File(keyStorePath)); trustStore.load(instream, keyStorepass.toCharArray()); // 相信自己的CA和所有自签名的证书 sc = SSLContexts.custom().loadTrustMaterial(trustStore, new TrustSelfSignedStrategy()).build(); } catch (KeyStoreException | NoSuchAlgorithmException| CertificateException | IOException | KeyManagementException e) { e.printStackTrace(); } finally { try { instream.close(); } catch (IOException e) { } } return sc; } ~~~      然后修改原来的send方法: ~~~ /** * 模拟请求 * * @param url 资源地址 * @param map 参数列表 * @param encoding 编码 * @return * @throws ParseException * @throws IOException * @throws KeyManagementException * @throws NoSuchAlgorithmException * @throws ClientProtocolException */ public static String send(String url, Map map,String encoding) throws ClientProtocolException, IOException { String body = ""; //tomcat是我自己的密钥库的密码,你可以替换成自己的 //如果密码为空,则用"nopassword"代替 SSLContext sslcontext = custom("D:\\keys\\wsriakey", "tomcat"); // 设置协议http和https对应的处理socket链接工厂的对象 Registry socketFactoryRegistry = RegistryBuilder.create() .register("http", PlainConnectionSocketFactory.INSTANCE) .register("https", new SSLConnectionSocketFactory(sslcontext)) .build(); PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry); HttpClients.custom().setConnectionManager(connManager); //创建自定义的httpclient对象 CloseableHttpClient client = HttpClients.custom().setConnectionManager(connManager).build(); // CloseableHttpClient client = HttpClients.createDefault(); //创建post方式请求对象 HttpPost httpPost = new HttpPost(url); //装填参数 List nvps = new ArrayList(); if(map!=null){ for (Entry entry : map.entrySet()) { nvps.add(new BasicNameValuePair(entry.getKey(), entry.getValue())); } } //设置参数到请求对象中 httpPost.setEntity(new UrlEncodedFormEntity(nvps, encoding)); System.out.println("请求地址:"+url); System.out.println("请求参数:"+nvps.toString()); //设置header信息 //指定报文头【Content-type】、【User-Agent】 httpPost.setHeader("Content-type", "application/x-www-form-urlencoded"); httpPost.setHeader("User-Agent", "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt)"); //执行请求操作,并拿到结果(同步阻塞) CloseableHttpResponse response = client.execute(httpPost); //获取结果实体 HttpEntity entity = response.getEntity(); if (entity != null) { //按指定编码转换结果实体为String类型 body = EntityUtils.toString(entity, encoding); } EntityUtils.consume(entity); //释放链接 response.close(); return body; } ~~~      测试一下吧: ~~~ public static void main(String[] args) throws ParseException, IOException, KeyManagementException, NoSuchAlgorithmException{ String url = "https://sso.tgb.com:8443/cas/login"; String body = send(url, null, "utf-8"); System.out.println("交易响应结果长度:"+body.length()); System.out.println("-----------------------------------"); url = "https://kyfw.12306.cn/otn/"; body = send(url, null, "utf-8"); System.out.println("交易响应结果长度:"+body.length()); } ~~~      测试结果: ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-02-18_56c53cb7ae964.jpg)      从结果中,我们很清楚的看到,使用自签名的证书,访问自签名的网站可以正常访问,访问12306则会失败。所以自签名的也只能用于自定义密钥和证书的情况下使用。而12306这种情况还是要用上一篇提到的“[绕过证书验证](http://blog.csdn.net/xiaoxian8023/article/details/49865335)”方案。
';

轻松把玩HttpClient之配置ssl,采用绕过证书验证实现https

最后更新于:2022-04-01 22:59:46

     版权声明:本文为博主原创文章,未经博主允许不得转载。如需转载请声明:【转自 http://blog.csdn.net/xiaoxian8023 】      上篇文章说道httpclient不能直接访问https的资源,这次就来模拟一下环境,然后配置https测试一下。在前面的文章中,分享了一篇自己生成并在tomcat中配置ssl的文章《[Tomcat配置SSL](http://blog.csdn.net/xiaoxian8023/article/details/49619777)》,大家可以据此来在本地配置https。我已经配置好了,效果是这样滴: ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-02-18_56c53cb7734f2.jpg)      可以看到已经信任该证书(显示浅绿色小锁),浏览器可以正常访问。现在我们用代码测试一下: ~~~ public static void main(String[] args) throws ParseException, IOException, KeyManagementException, NoSuchAlgorithmException, HttpProcessException { String url = "https://sso.tgb.com:8443/cas/login"; String body = send(url, null, "utf-8"); System.out.println("交易响应结果:"); System.out.println(body); System.out.println("-----------------------------------"); } ~~~ ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-02-18_56c53cb785c80.jpg)      发现抛出了异常,我知道的有两种方案(也许还有我不知道的方案),这里介绍第一种方案,也是用的比较多的方案——绕过证书验证。直接看代码吧: ~~~ /** * 绕过验证 * * @return * @throws NoSuchAlgorithmException * @throws KeyManagementException */ public static SSLContext createIgnoreVerifySSL() throws NoSuchAlgorithmException, KeyManagementException { SSLContext sc = SSLContext.getInstance("SSLv3"); // 实现一个X509TrustManager接口,用于绕过验证,不用修改里面的方法 X509TrustManager trustManager = new X509TrustManager() { @Override public void checkClientTrusted( java.security.cert.X509Certificate[] paramArrayOfX509Certificate, String paramString) throws CertificateException { } @Override public void checkServerTrusted( java.security.cert.X509Certificate[] paramArrayOfX509Certificate, String paramString) throws CertificateException { } @Override public java.security.cert.X509Certificate[] getAcceptedIssuers() { return null; } }; sc.init(null, new TrustManager[] { trustManager }, null); return sc; } ~~~      然后修改原来的send方法: ~~~ /** * 模拟请求 * * @param url 资源地址 * @param map 参数列表 * @param encoding 编码 * @return * @throws NoSuchAlgorithmException * @throws KeyManagementException * @throws IOException * @throws ClientProtocolException */ public static String send(String url, Map map,String encoding) throws KeyManagementException, NoSuchAlgorithmException, ClientProtocolException, IOException { String body = ""; //采用绕过验证的方式处理https请求 SSLContext sslcontext = createIgnoreVerifySSL(); // 设置协议http和https对应的处理socket链接工厂的对象 Registry socketFactoryRegistry = RegistryBuilder.create() .register("http", PlainConnectionSocketFactory.INSTANCE) .register("https", new SSLConnectionSocketFactory(sslcontext)) .build(); PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry); HttpClients.custom().setConnectionManager(connManager); //创建自定义的httpclient对象 CloseableHttpClient client = HttpClients.custom().setConnectionManager(connManager).build(); // CloseableHttpClient client = HttpClients.createDefault(); //创建post方式请求对象 HttpPost httpPost = new HttpPost(url); //装填参数 List nvps = new ArrayList(); if(map!=null){ for (Entry entry : map.entrySet()) { nvps.add(new BasicNameValuePair(entry.getKey(), entry.getValue())); } } //设置参数到请求对象中 httpPost.setEntity(new UrlEncodedFormEntity(nvps, encoding)); System.out.println("请求地址:"+url); System.out.println("请求参数:"+nvps.toString()); //设置header信息 //指定报文头【Content-type】、【User-Agent】 httpPost.setHeader("Content-type", "application/x-www-form-urlencoded"); httpPost.setHeader("User-Agent", "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt)"); //执行请求操作,并拿到结果(同步阻塞) CloseableHttpResponse response = client.execute(httpPost); //获取结果实体 HttpEntity entity = response.getEntity(); if (entity != null) { //按指定编码转换结果实体为String类型 body = EntityUtils.toString(entity, encoding); } EntityUtils.consume(entity); //释放链接 response.close(); return body; } ~~~      现在再进行测试,发现果然通了。 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-02-18_56c53cb79b02e.jpg)      下篇介绍另一种方案,应对自己生成的证书,敬请期待。
';

轻松把玩HttpClient之模拟post请求示例

最后更新于:2022-04-01 22:59:44

     版权声明:本文为博主原创文章,未经博主允许不得转载。如需转载请声明:【转自 http://blog.csdn.net/xiaoxian8023 】      HttpClient 是 Apache Jakarta Common 下的子项目,可以用来提供高效的、最新的、功能丰富的支持 HTTP 协议的客户端编程工具包,并且它支持 HTTP 协议最新的版本和建议。当前官网最新版介绍页是:[http://hc.apache.org/httpcomponents-client-4.5.x/index.html](http://hc.apache.org/httpcomponents-client-4.5.x/index.html)      许多需要后台模拟请求的系统或者框架都用的是httpclient。所以作为一个java开发人员,有必要学一学。本文提供了一个简单的demo,供初学者参考。      使用HttpClient发送请求、接收响应很简单,一般需要如下几步即可: 1. 创建CloseableHttpClient对象。 2. 创建请求方法的实例,并指定请求URL。如果需要发送GET请求,创建HttpGet对象;如果需要发送POST请求,创建HttpPost对象。 3. 如果需要发送请求参数,可可调用setEntity(HttpEntity entity)方法来设置请求参数。setParams方法已过时(4.4.1版本)。 4. 调用HttpGet、HttpPost对象的setHeader(String name, String value)方法设置header信息,或者调用setHeaders(Header[] headers)设置一组header信息。 5. 调用CloseableHttpClient对象的execute(HttpUriRequest request)发送请求,该方法返回一个CloseableHttpResponse。 6. 调用HttpResponse的getEntity()方法可获取HttpEntity对象,该对象包装了服务器的响应内容。程序可通过该对象获取服务器的响应内容;调用CloseableHttpResponse的getAllHeaders()、getHeaders(String name)等方法可获取服务器的响应头。 7. 释放连接。无论执行方法是否成功,都必须释放连接      具体代码如下(HttpClient-4.4.1): ~~~ /** * 简单httpclient实例 * * @author arron * @date 2015年11月11日 下午6:36:49 * @version 1.0 */ public class SimpleHttpClientDemo { /** * 模拟请求 * * @param url 资源地址 * @param map 参数列表 * @param encoding 编码 * @return * @throws ParseException * @throws IOException */ public static String send(String url, Map map,String encoding) throws ParseException, IOException{ String body = ""; //创建httpclient对象 CloseableHttpClient client = HttpClients.createDefault(); //创建post方式请求对象 HttpPost httpPost = new HttpPost(url); //装填参数 List nvps = new ArrayList(); if(map!=null){ for (Entry entry : map.entrySet()) { nvps.add(new BasicNameValuePair(entry.getKey(), entry.getValue())); } } //设置参数到请求对象中 httpPost.setEntity(new UrlEncodedFormEntity(nvps, encoding)); System.out.println("请求地址:"+url); System.out.println("请求参数:"+nvps.toString()); //设置header信息 //指定报文头【Content-type】、【User-Agent】 httpPost.setHeader("Content-type", "application/x-www-form-urlencoded"); httpPost.setHeader("User-Agent", "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt)"); //执行请求操作,并拿到结果(同步阻塞) CloseableHttpResponse response = client.execute(httpPost); //获取结果实体 HttpEntity entity = response.getEntity(); if (entity != null) { //按指定编码转换结果实体为String类型 body = EntityUtils.toString(entity, encoding); } EntityUtils.consume(entity); //释放链接 response.close(); return body; } public static void main(String[] args) throws ParseException, IOException { String url="http://php.weather.sina.com.cn/iframe/index/w_cl.php"; Map map = new HashMap(); map.put("code", "js"); map.put("day", "0"); map.put("city", "上海"); map.put("dfc", "1"); map.put("charset", "utf-8"); String body = send(url, map,"utf-8"); System.out.println("交易响应结果:"); System.out.println(body); } } ~~~      在main方法中测试一下: ~~~ public static void main(String[] args) throws ParseException, IOException { String url="http://php.weather.sina.com.cn/iframe/index/w_cl.php"; Map map = new HashMap(); map.put("code", "js"); map.put("day", "0"); map.put("city", "上海"); map.put("dfc", "1"); map.put("charset", "utf-8"); String body = send(url, map,"utf-8"); System.out.println("交易响应结果:"); System.out.println(body); System.out.println("-----------------------------------"); map.put("city", "北京"); body = send(url, map, "utf-8"); System.out.println("交易响应结果:"); System.out.println(body); } ~~~      结果如下: ~~~ 请求地址:http://php.weather.sina.com.cn/iframe/index/w_cl.php 请求参数:[dfc=1, charset=utf-8, day=0, code=js, city=上海] 交易响应结果: (function(){var w=[];w['上海']=[{s1:'小雨',s2:'小雨',f1:'xiaoyu',f2:'xiaoyu',t1:'21',t2:'16',p1:'≤3',p2:'≤3',d1:'南风',d2:'北风'}];var add={now:'2015-11-16 13:16:23',time:'1447650983',update:'北京时间11月16日08:10更新',error:'0',total:'1'};window.SWther={w:w,add:add};})();//0 ----------------------------------- 请求地址:http://php.weather.sina.com.cn/iframe/index/w_cl.php 请求参数:[dfc=1, charset=utf-8, day=0, code=js, city=北京] 交易响应结果: (function(){var w=[];w['北京']=[{s1:'多云',s2:'多云',f1:'duoyun',f2:'duoyun',t1:'9',t2:'1',p1:'≤3',p2:'≤3',d1:'无持续风向',d2:'无持续风向'}];var add={now:'2015-11-16 13:18:35',time:'1447651115',update:'北京时间11月16日08:10更新',error:'0',total:'1'};window.SWther={w:w,add:add};})();//0 ~~~      现在我们测试一下https链接:https://www.qingyidai.com/investmanagement/invest.shtml ~~~ public static void main(String[] args) throws ParseException, IOException { String url = "https://www.qingyidai.com/investmanagement/invest.shtml"; String body = send(url, null, "utf-8"); System.out.println("交易响应结果:"); System.out.println(body); } ~~~      结果发现,居然正常拿到结果了: ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-02-18_56c53cb7597de.jpg)      原来如果网站的证书已经被ca机构认证通过了,那么用HttpClient来调用的话,会直接成功的。不用再单独配置htts链接了。不过如果是自生成的证书,还是需要配置https的,下篇就来配置一下吧,敬请期待。
';

简单的利用UrlConnection,后台模拟http请求

最后更新于:2022-04-01 22:59:41

     版权声明:本文为博主原创文章,未经博主允许不得转载。如需转载请声明:【转自 http://blog.csdn.net/xiaoxian8023 】      这两天在整理看httpclient,然后想自己用UrlConnection后台模拟实现Http请求,于是一个简单的小例子就新鲜出炉了(支持代理哦): ~~~ public class SimpleHttpTest { public static String send(String urlStr, Map map,String encoding){ String body=""; StringBuffer sbuf = new StringBuffer(); if(map!=null){ for (Entry entry : map.entrySet()) { sbuf.append(entry.getKey()).append("=").append(entry.getValue()).append("&"); } if(sbuf.length()>0){ sbuf.deleteCharAt(sbuf.length()-1); } } // 1、重新对请求报文进行 GBK 编码 byte[] postData = null; try { postData = sbuf.toString().getBytes(encoding); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } // 2、发送 HTTP(S) 请求 OutputStream reqStream = null; InputStream resStream = null; URLConnection request = null; try { System.out.println("交易请求地址:" + urlStr); System.out.println("参数:" + sbuf.toString()); //A、与服务器建立 HTTP(S) 连接 URL url = null; try { Proxy proxy = new Proxy(java.net.Proxy.Type.HTTP,new InetSocketAddress("127.0.0.1", 8087)); url = new URL(urlStr); request = url.openConnection(proxy); request.setDoInput(true); request.setDoOutput(true); } catch (MalformedURLException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } //B、指定报文头【Content-type】、【Content-length】 与 【Keep-alive】 request.setRequestProperty("Content-type", "application/x-www-form-urlencoded"); request.setRequestProperty("Content-length", String.valueOf(postData.length)); request.setRequestProperty("Keep-alive", "false"); request.setRequestProperty("User-Agent", "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt)"); //C、发送报文至服务器 reqStream = request.getOutputStream(); reqStream.write(postData); reqStream.close(); //D、接收服务器返回结果 ByteArrayOutputStream ms = null; resStream = request.getInputStream(); ms = new ByteArrayOutputStream(); byte[] buf = new byte[4096]; int count; while ((count = resStream.read(buf, 0, buf.length)) > 0) { ms.write(buf, 0, count); } resStream.close(); body = new String(ms.toByteArray(), encoding); } catch (UnknownHostException e) { System.err.println( "服务器不可达【" + e.getMessage() + "】"); } catch (IOException e) { e.printStackTrace(); } finally { try { if (reqStream != null) reqStream.close(); if (resStream != null) resStream.close(); } catch (Exception ex) { } } System.out.println("交易响应结果:"); System.out.println(body); return body; } public static void main(String[] args) { String url="http://php.weather.sina.com.cn/iframe/index/w_cl.php"; Map map = new HashMap(); map.put("code", "js"); map.put("day", "0"); map.put("city", "上海"); map.put("dfc", "1"); map.put("charset", "utf-8"); send(url, map,"utf-8"); } } ~~~      结果如下: ~~~ 交易请求地址:http://php.weather.sina.com.cn/iframe/index/w_cl.php 参数:dfc=1&charset=utf-8&day=0&code=js&city=上海 交易响应结果: (function(){var w=[];w['上海']=[{s1:'阴',s2:'阴',f1:'yin',f2:'yin',t1:'17',t2:'14',p1:'≤3',p2:'≤3',d1:'东北风',d2:'东北风'}];var add={now:'2015-11-11 19:04:33',time:'1447239873',update:'北京时间11月11日17:10更新',error:'0',total:'1'};window.SWther={w:w,add:add};})();//0 ~~~      代码中的步骤写的很明白了,如果你有心,还可以对该方法进行各种封装,方便使用。下篇我会分享一下httpclient是如何模拟后台来发送http请求的,还有配置ssl、代理、自定义header等等,敬请期待吧。
';

httpclient3.x中使用HTTPS的方法

最后更新于:2022-04-01 22:59:39

     版权声明:本文为博主原创文章,未经博主允许不得转载。如需转载请声明:【转自 http://blog.csdn.net/xiaoxian8023 】     HttpClient请求https的实例: ~~~ import javax.net.ssl.SSLContext; import javax.net.ssl.TrustManager; import javax.net.ssl.X509TrustManager; import java.security.cert.CertificateException; import java.security.cert.X509Certificate; import org.apache.http.client.ClientProtocolException; import org.apache.http.client.HttpClient; import org.apache.http.client.ResponseHandler; import org.apache.http.client.methods.HttpGet; import org.apache.http.conn.ClientConnectionManager; import org.apache.http.conn.scheme.Scheme; import org.apache.http.conn.scheme.SchemeRegistry; import org.apache.http.conn.scheme.SchemeSocketFactory; import org.apache.http.conn.ssl.SSLSocketFactory; import org.apache.http.impl.client.BasicResponseHandler; import org.apache.http.impl.client.ClientParamsStack; import org.apache.http.impl.client.DefaultHttpClient; import org.apache.http.params.DefaultedHttpParams; import org.apache.http.params.HttpParams; public class HttpClientTest { public static void main(String args[]) { try { HttpClient httpclient = new DefaultHttpClient(); //Secure Protocol implementation. SSLContext ctx = SSLContext.getInstance("SSL"); //Implementation of a trust manager for X509 certificates X509TrustManager tm = new X509TrustManager() { public void checkClientTrusted(X509Certificate[] xcs, String string) throws CertificateException { } public void checkServerTrusted(X509Certificate[] xcs, String string) throws CertificateException { } public X509Certificate[] getAcceptedIssuers() { return null; } }; ctx.init(null, new TrustManager[] { tm }, null); SSLSocketFactory ssf = new SSLSocketFactory(ctx); ClientConnectionManager ccm = httpclient.getConnectionManager(); //register https protocol in httpclient's scheme registry SchemeRegistry sr = ccm.getSchemeRegistry(); sr.register(new Scheme("https", 443, ssf)); HttpGet httpget = new HttpGet(""); HttpParams params = httpclient.getParams(); params.setParameter("param1", "paramValue1"); httpget.setParams(params); System.out.println("REQUEST:" + httpget.getURI()); ResponseHandler responseHandler = new BasicResponseHandler(); String responseBody; responseBody = httpclient.execute(httpget, responseHandler); System.out.println(responseBody); // Create a response handler } catch (NoSuchAlgorithmException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (ClientProtocolException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (Exception ex) { ex.printStackTrace(); } } } ~~~
';

HttpClient3.x之Get请求和Post请求示例

最后更新于:2022-04-01 22:59:37

     版权声明:本文为博主原创文章,未经博主允许不得转载。如需转载请声明:【转自 http://blog.csdn.net/xiaoxian8023 】      HttpClient的支持在HTTP/1.1规范中定义的所有的HTTP方法:GET, HEAD, POST, PUT, DELETE, TRACE 和 OPTIONS。每有一个方法都有一个对应的类:HttpGet,HttpHead,HttpPost,HttpPut,HttpDelete,HttpTrace和HttpOptions。所有的这些类均实现了HttpUriRequest接口,故可以作为execute的执行参数使用。请求URI是能够应用请求的统一资源标识符。 HTTP请求的URI包含一个协议计划protocol scheme,主机名host name,,可选的端口optional port,资源的路径resource path,可选的查询optional query和可选的片段optional fragment。      head,put,delete,trace HttpClient支持这些方法, 大多数浏览器不支持这些方法,原因是Html 4中对 FORM 的method方法只支持两个get和post,很多浏览器还都依然是基于html4的。      通常会在JAVA中通过代码调用URL进行远端方法调用,这些方法有的是Get请求方式的,有的是POST请求方式的,为此,总结一例,贴出以便查阅。      依赖JAR包有:commons-codec.jar,commons-httpclient.jar,commons-logging.jar。 ~~~ package com.wujintao.httpclient; import java.io.IOException; import java.io.InputStream; import org.apache.commons.httpclient.DefaultHttpMethodRetryHandler; import org.apache.commons.httpclient.HttpClient; import org.apache.commons.httpclient.HttpException; import org.apache.commons.httpclient.HttpStatus; import org.apache.commons.httpclient.NameValuePair; import org.apache.commons.httpclient.methods.GetMethod; import org.apache.commons.httpclient.methods.PostMethod; import org.apache.commons.httpclient.params.HttpMethodParams; import org.junit.Test; public class TestCase { @Test public void testGetRequest() throws IllegalStateException, IOException { HttpClient client = new HttpClient(); StringBuilder sb = new StringBuilder(); InputStream ins = null; // Create a method instance. GetMethod method = new GetMethod("http://www.baidu.com"); // Provide custom retry handler is necessary method.getParams().setParameter(HttpMethodParams.RETRY_HANDLER, new DefaultHttpMethodRetryHandler(3, false)); try { // Execute the method. int statusCode = client.executeMethod(method); System.out.println(statusCode); if (statusCode == HttpStatus.SC_OK) { ins = method.getResponseBodyAsStream(); byte[] b = new byte[1024]; int r_len = 0; while ((r_len = ins.read(b)) > 0) { sb.append(new String(b, 0, r_len, method .getResponseCharSet())); } } else { System.err.println("Response Code: " + statusCode); } } catch (HttpException e) { System.err.println("Fatal protocol violation: " + e.getMessage()); } catch (IOException e) { System.err.println("Fatal transport error: " + e.getMessage()); } finally { method.releaseConnection(); if (ins != null) { ins.close(); } } System.out.println(sb.toString()); } @Test public void testPostRequest() throws HttpException, IOException { HttpClient client = new HttpClient(); PostMethod method = new PostMethod("http://www.baidu.com/getValue"); method.setRequestHeader("Content-Type", "application/x-www-form-urlencoded;charset=gb2312"); NameValuePair[] param = { new NameValuePair("age", "11"), new NameValuePair("name", "jay"), }; method.setRequestBody(param); int statusCode = client.executeMethod(method); System.out.println(statusCode); method.releaseConnection(); } } ~~~
';

前言

最后更新于:2022-04-01 22:59:35

> 原文出处:[轻松把玩HttpClient](http://blog.csdn.net/column/details/httpclient-arron.html) 作者:[崔成龙](http://blog.csdn.net/xiaoxian8023) **本系列文章经作者授权在看云整理发布,未经作者允许,请勿转载!** # 轻松把玩HttpClient > 介绍如何使用HttpClient,通过一些简单示例,来帮助初学者快速入手。最后提供了一个非常强大的工具类,比现在网络上分享的都强大,支持插件式设置header、代理、ssl等配置信息。
';