一,使用HttpClient发送请求、接收响应在项目中是经常使用的,使用也很简单,常见的有如下几步:
1. 创建对象:HttpClient对象。
2. 创建请求方法的实例,并指定请求URL。如果需要发送GET请求,创建HttpGet对象;如果需要发送POST请求,创建HttpPost对象。
3. 如果需要发送请求参数,可调用HttpGet、HttpPost共同的setParams(HetpParams params)方法来添加请求参数;对于HttpPost对象而言,也可调用setEntity(HttpEntity entity)方法来设置请求参数。
4. 调用HttpClient对象的execute(HttpUriRequest request)发送请求,该方法返回一个HttpResponse。
5. 调用HttpResponse的getAllHeaders()、getHeaders(String name)等方法可获取服务器的响应头;调用HttpResponse的getEntity()方法可获取HttpEntity对象,该对象包装了服务器的响应内容。程序可通过该对象获取服务器的响应内容。
6. 释放连接。无论执行方法是否成功,都必须释放连接。
二, 使用HttpClient遇到的问题。
1)字符编码
某目标页的编码可能出现在两个地方,第一个地方是服务器返回的http头中,另外一个地方是得到的html/xml页面中。
在http头的Content-Type字段可能会包含字符编码信息。例如可能返回的头会包含这样子的信息:Content-Type: text/html; charset=UTF-8。这个头信息表明该页的编码是UTF-8,但是服务器返回的头信息未必与内容能匹配上。比如对于一些双字节语言国家,可能服务器返回的编码类型是UTF-8,但真正的内容却不是UTF-8编码的,因此需要在另外的地方去得到页面的编码信息;但是如果服务器返回的编码不是UTF-8,而是具体的一些编码,比如gb2312等,那服务器返回的可能是正确的编码信息。通过method对象的getResponseCharSet()方法就可以得到http头中的编码信息。
对于象xml或者html这样的文件,允许作者在页面中直接指定编码类型。比如在html中会有``这样的标签;或者在xml中会有``这样的标签,在这些情况下,可能与http头中返回的编码信息冲突,需要用户自己判断到底那种编码类型应该是真正的编码。
2)自动转向
根据RFC2616中对自动转向的定义,主要有两种:301和302。301表示永久的移走(Moved
Permanently),当返回的是301,则表示请求的资源已经被移到一个固定的新地方,任何向该地址发起请求都会被转到新的地址上。302表示暂时的转向,比如在服务器端的servlet程序调用了sendRedirect方法,则在客户端就会得到一个302的代码,这时服务器返回的头信息中location的值就是sendRedirect转向的目标地址。
HttpClient支持自动转向处理,但是像 POST 和 PUT 方式这种要求接受后继服务的请求方式,暂时不支持自动转向,因此如果遇到 POST 方式提交后返回的是 301或者302 的话需要自己处理。
另外除了在头中包含的信息可能使页面发生重定向外,在页面中也有可能会发生页面的重定向。引起页面自动转发的标签是:``。如果你想在程序中也处理这种情况的话得自己分析页面来实现转向。需要注意的是,在上面那个标签中 url 的值也可以是一个相对地址,如果是这样的话,需要对它做一些处理后才可以转发。
3)Demo 如下:
Demo1- 无参数的 get请求发送。
/** * 处理get请求. * @param url 请求路径 * @return json */ public String getTest(String url){ //实例化httpclient CloseableHttpClient httpclient = HttpClients.createDefault(); //实例化get方法 HttpGet httpget = new HttpGet(url); //请求结果 CloseableHttpResponse response = null; String content =""; try { //执行get方法 response = httpclient.execute(httpget); if(response.getStatusLine().getStatusCode() == 200){ content = EntityUtils.toString(response.getEntity(),"utf-8"); log.debug("content: {}", content); } } catch (ClientProtocolException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } return content; }
Demo2- 无参数的 get 请求发送。
/** * 发送Get 请求 * * @param url 请求URL * @return json */ public static String sendGet(String url) { //1.获得一个httpclient对象 CloseableHttpClient httpclient = HttpClients.createDefault(); //2.生成一个get请求 HttpGet httpget = new HttpGet(url); CloseableHttpResponse response = null; try { //3.执行get请求并返回结果 response = httpclient.execute(httpget); } catch (IOException e1) { e1.printStackTrace(); } String result = null; try { //4.处理结果,这里将结果返回为字符串 HttpEntity entity = response.getEntity(); if (entity != null) { result = EntityUtils.toString(entity); log.debug("result ---------- {}", result); } } catch (ParseException | IOException e) { e.printStackTrace(); } finally { try { response.close(); } catch (IOException e) { e.printStackTrace(); } } return result; }
Demo3- 有参数的 post 请求发送。
/** * 处理有参数的 post请求.测试1 * @param url 请求路径 * @param params 参数 * @return json */ public String postTest(String url, Mapparams){ //实例化httpClient CloseableHttpClient httpclient = HttpClients.createDefault(); //实例化post方法 HttpPost httpPost = new HttpPost(url); //处理参数 List nvps = new ArrayList (); Set keySet = params.keySet(); for(String key : keySet) { nvps.add(new BasicNameValuePair(key, params.get(key))); } //结果 CloseableHttpResponse response = null; String content=""; try { //提交的参数 UrlEncodedFormEntity uefEntity = new UrlEncodedFormEntity(nvps, "UTF-8"); //将参数给post方法 httpPost.setEntity(uefEntity); //执行post方法 response = httpclient.execute(httpPost); if(response.getStatusLine().getStatusCode() == 200){ content = EntityUtils.toString(response.getEntity(),"utf-8"); log.debug("content ---------- {}", content); } } catch (ClientProtocolException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } return content; }
/** * 有参数的 post 测试2 * * @param url * @param map * @return */ public static String sendPost(String url, Mapmap) { CloseableHttpClient httpclient = HttpClients.createDefault(); List formparams = new ArrayList (); for (Map.Entry entry : map.entrySet()) { //给参数赋值 formparams.add(new BasicNameValuePair(entry.getKey(), entry.getValue())); } UrlEncodedFormEntity entity = new UrlEncodedFormEntity(formparams, Consts.UTF_8); HttpPost httppost = new HttpPost(url); httppost.setEntity(entity); CloseableHttpResponse response = null; try { response = httpclient.execute(httppost); } catch (IOException e) { e.printStackTrace(); } HttpEntity entity1 = response.getEntity(); String result = null; try { result = EntityUtils.toString(entity1); } catch (ParseException | IOException e) { e.printStackTrace(); } return result; }
Demo4- 无 参数的 post 请求发送。
/** * 发送HttpPost的方法和发送HttpGet很类似,只是将请求类型给位HttpPost即可。 * 发送 不带参数的 HttpPost请求 * @param url * @return */ public static String sendPostNoParams(String url) { //1.获得一个httpclient对象 CloseableHttpClient httpclient = HttpClients.createDefault(); //2.生成一个post请求 HttpPost httppost = new HttpPost(url); CloseableHttpResponse response = null; try { //3.执行get请求并返回结果 response = httpclient.execute(httppost); } catch (IOException e) { e.printStackTrace(); } //4.处理结果,这里将结果返回为字符串 HttpEntity entity = response.getEntity(); String result = null; try { result = EntityUtils.toString(entity); log.debug("result: {}", result); } catch (ParseException | IOException e) { e.printStackTrace(); } return result; }