基于springboot的httpclient封装
概述
详细
一、使用场景
目前C/S还是B/S结构的应用程序, HTTP 应该是最为广泛使用的协议了。在 Java 平台上,Java 标准库提供了 一个HttpURLConnection 类来支持 HTTP 通讯。不过 HttpURLConnection 本身的 API 不够友好,所提供的功能也有限。httpClien是一个实现http协议很多操作功能的组件,并且它支持 HTTP 协议最新的版本和建议,现在Android已经成功的集成了HttpClient。另外,最新由Square 公司开源的 OkHttp 据说能提供更高效率的http连接,支持GZIP 压缩和 HTTP 响应缓存功能,在原理上应该是大同小异的。
二、httpclient的使用步骤
利用httpclient去访问接口的步骤一般是:
1. 创建HttpClient对象。2. 构造Http 请求对象。3. 执行HttpClient对象的execute方法,将Http请求对象作为该方法的参数。4. 读取execute方法返回的HttpResponse结果并解析。5、释放连接。整个过程是不是与我们平时在浏览器上访问类似呢。唯一区别是不能执行HTTP页面中签入嵌入的JS代码,自然也不会对页面内容进行任何解析、处理,这些都是需要开发人员来完成的。在以上代码中,httpclient的初始化没有看到任何参数设置,其实是在它的构造函数里调用了接口,并设置了默认值,如下包含协议版本、客户端引擎、cookie策略等,如果要自己设置,可以通过它的成员变量httpClientParams对象进行设置。
1、关于重定向。
http多种状态已经在HttpStatus这个类中定义好,其中重定向 根据RFC2616中对自动转向的定义,主要有两种:301和302。301表示永久的移走(Moved Permanently),当返回的是301,则表示请求的资源已经被移到一个固定的新地方,任何向该地址发起请求都会被转到新的地址上。302表示暂时的转向,比如在服务器端的servlet程序调用了sendRedirect方法,则在客户端就会得到一个302的代码,这时服务器返回的头信息中location的值就是sendRedirect转向的目标地址。如果是get方式请求,httpclient是自动帮你重定向并拿到响应信息,也可以通过设置method.setFollowRedirects(false)不自动转。post的请求是不能自动跳转的,需要从头部信息中拿到Location(可能是相对路径)因此需要对location返回的值做一些处理才可以发起向新地址的请求。
2、字符编码
客户端发送的数据多样,最终所有数据都是通过最底层的物理层面的电信号来传递,首部字段content-type 说明了实体主体内对象的媒体类型,即服务器通过contentType来知道这个是什么样子的数据。客户端在拿到服务器返回的数据后,根据头部设置的可接收媒体类型进行内容协商,返回最适合的资源。对于有中文的请求,为避免出现乱码,最好设置content-type。在上部分的代码截图,大家可以看到,如果我们自己不设置contentType 那么默认会采用ISO的方式进行传输,那么如果与你实际的编码方式不一致的话,服务器就会拿到一个乱码,从而无法正常的响应。可以通过上面代码进行设置,也可以通过method.setRequestHeader("Content-Type", " application/json; charset=UTF-8")来进行设置
3、cookie
httpclient默认的cookie策略是RFC_2109其中可以通过去更改。请求过程中可以通过sendHead 把cookie放入头部,并传到后端进行访问。
三、代码实现
在pom文件引入httpclient相关的jar包
<!-- https://mvnrepository.com/artifact/org.apache.commons/commons-lang3 --> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-lang3</artifactId> <version>3.8</version> </dependency> <dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpclient</artifactId> </dependency> <dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpmime</artifactId> </dependency> <dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpasyncclient</artifactId> </dependency> <!-- <dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpasyncclient</artifactId> <version>4.1</version> </dependency> --> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.17</version> </dependency>
2.创建httpclient模拟请求接口
/** * 模拟请求 * * @param url 资源地址 * @param paraMap 参数列表 * @param encoding 编码 * @return * @throws NoSuchAlgorithmException * @throws KeyManagementException * @throws IOException * @throws ClientProtocolException */ public static String send(String url, Map<String,String> paraMap,String encoding) throws KeyManagementException, NoSuchAlgorithmException, ClientProtocolException, IOException { String body = ""; SSLContext sslcontext = createIgnoreVerifySSL(); // 设置协议http和https对应的处理socket链接工厂的对象 Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory>create() .register("http", PlainConnectionSocketFactory.INSTANCE) .register("https", new SSLConnectionSocketFactory(sslcontext)) .build(); PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry); //创建自定义的httpclient对象 CloseableHttpClient client = HttpClients.createDefault(); //创建post方式请求对象 HttpPost httpPost = new HttpPost(url); //装填参数 List<NameValuePair> nvps = new ArrayList<NameValuePair>(); if(paraMap!=null){ for (Entry<String, String> entry : paraMap.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; }
3.模拟请求接口
@Test public void testPost() throws KeyManagementException, NoSuchAlgorithmException, ClientProtocolException, IOException { String testUrl = "http://localhost:8080/test"; Map<String, String> paraMap = new HashMap(); paraMap.put("name", "lilei"); paraMap.put("age", "8"); String body = HttpClientUtil.send(testUrl, paraMap, "utf-8"); System.out.println("请求响应结果:"); System.out.println(body); System.out.println("-----------------------------------"); }
四、代码演示
五、代码结构
六、小结
基本上使用httpclient过程中,主要操作的类有:httpclient,getMethod,postMethod,httpClientParams,httpConnectionManager这几个。详见以下的类图。
HttpClient代表了一个http的客户端,HttpConnectionManager是用来管理HttpConnection 的,HttpConnection代表了一个http连接,所以HttpConnectionManager其实质上也就是一个http连接池,管理这些 http连接(和数据库连接池一个道理)。HttpMethod代表了一个Http方法,一个HttpClient可以运行多个HttpMethod(实 质上,httpclient执行一个HttpMethod时,会从connectionmanager那里获取一个httpconnection,在此 connection上执行该method,执行完该method后,让method 释放该httpconnection,从而将该httpconnection返回给connectionmanager,以便供后续的method使 用)所以在httpclient连接后资源释放问题很重要,就跟我们用database connection要释放资源一样。