本文主要大致介绍HttpClient(基于HttpClient 4.5)及如何使用,附HttpUtil工具类。
一、HttpClient使用流程
1、创建HttpClient对象
2、创建请求方法的实例,并指定请求URL。如果需要发送GET请求,创建HttpGet对象;如果需要发送POST请求,创建HttpPost对象。
3、如果需要发送请求参数,可调用HttpGetsetParams方法来添加请求参数;对于HttpPost对象而言,可调用setEntity(HttpEntity entity)方法来设置请求参数。
4、调用HttpClient对象的execute(HttpUriRequest request)发送请求,该方法返回一个HttpResponse对象。
5、调用HttpResponse的getAllHeaders()、getHeaders(String name)等方法可获取服务器的响应头;调用HttpResponse的getEntity()方法可获取HttpEntity对象,该对象包装了服务器的响应内容。程序可通过该对象获取服务器的响应内容。
6、释放连接。无论执行方法是否成功,都必须释放连接
二、介绍
1、GET,HEAD, POST, PUT, DELETE, TRACE and OPTIONS.对应的HttpClient中的类型分别为HttpGet,HttpHead, HttpPost, HttpPut, HttpDelete, HttpTrace, and HttpOptions.
2、响应头,设置和获取响应头:
HttpResponse response = new BasicHttpResponse(HttpVersion.HTTP_1_1, HttpStatus.SC_OK, "OK"); response.addHeader("Set-Cookie", "c1=a; path=/; domain=localhost"); response.addHeader("Set-Cookie", "c2=b; path="/", c3=c; domain="localhost""); HeaderElementIterator it = new BasicHeaderElementIterator(response.headerIterator("Set-Cookie")); while (it.hasNext()) { HeaderElement elem = it.nextElement(); System.out.println(elem.getName() + " = " + elem.getValue()); NameValuePair[] params = elem.getParameters(); for (int i = 0; i < params.length; i++) { System.out.println(" " + params[i]); } }
3、HTTP entity
HTTP消息可以携带与请求或响应相关联的内容实体(entity)。对应请求报文中的请求主体和响应报文中的响应正文。
请求报文构成 | 请求报文由请求行(请求方式,URI和HTTP版本),请求头,空行(CR+LF,回车符+换行符),请求数据主体构成。 |
响应报文构成 | 响应报文由状态行(HTTP版本,状态码,原因),响应头,空行,响应正文构成。 |
根据内容的来源,HttpClient区分了三种实体:
1)streamed:内容以流的方式接收
2)self-contained:内容在内存中,或者通过独立于连接或其他实体的方式获取。self-contained实体通常是可重复的。这种类型的实体将主要用于封装HTTP请求的实体。
3)wrapping:内容是从另一个实体获得的
可重复的实体:意思是它的内容可以读取一次或多次,仅存在于self-contained实体类型,如ByteArrayEntity or StringEntity
API:
HttpEntity#getContent() 返回java.io.InputStream
HttpEntity#getContentType()、HttpEntity#getContentType() 获取响应的Content-Type、Content-Length响应头。
4、确保释放资源
httpClient、response及获取的流式的内容等都需要在finally块中进行close。
5、获取返回内容
推荐的使用实体内容的方法是使用它的HttpEntity#getContent()或HttpEntity#writeTo(OutputStream)方法。HttpClient还提供了EntityUtils类,它公开了几个静态方法,以便更容易地从实体中读取内容或信息。而不是读java.io。通过使用这个类中的方法,可以直接在astring / byte数组中检索整个内容体。但是,强烈建议不要使用EntityUtils,除非响应实体来自受信任的HTTP服务器,并且已知其长度有限。
... // http客户端 CloseableHttpClient httpclient = HttpClients.createDefault(); // get请求 HttpGet httpget = new HttpGet(url); CloseableHttpResponse response = null; try { response = httpclient.execute(httpget); HttpEntity entity = response.getEntity(); String content; if (entity != null) { long len = entity.getContentLength(); if (len != -1 && len < 2048) { content = EntityUtils.toString(entity); } else { // Stream content out InputStream instream = entity.getContent(); try { BufferedReader br = new BufferedReader(new InputStreamReader(instream, "UTF-8")); char[] buffer = new char[4096]; int length; StringBuilder sb = new StringBuilder(); while ((length = br.read(buffer)) > 0) { sb.append(new String(buffer, 0, length)); } content = sb.toString(); } finally { instream.close(); } } resultMap.put("content", content); } } ...
在一些情况下需要从entity中多次读取content,这时entity content需要缓存在内存或磁盘中。最简单方法是使用BufferedHttpEntity类包装原始实体,将原始实体的内容读入到内存缓冲区。
HttpEntity entity = response.getEntity(); if (entity != null) { entity=new BufferedHttpEntity(entity); }
6、写入entity content
HttpClient提供了几个类,可用于通过HTTP连接高效地传输内容。这些类的实例可以与封装请求(如POST和PUT)的实体相关联,以便将实体内容封装到传出HTTP请求中。HttpClient为最常见的数据容器提供了几个类,比如字符串、字节数组、输入流和文件:StringEntity、ByteArrayEntity、InputStreamEntity和FileEntity。
1)HTML forms
对应的Content-Type:application/x-www-form-urlencoded
List<NameValuePair> formparams = new ArrayList<NameValuePair>(); formparams.add(new BasicNameValuePair("param1", "value1")); formparams.add(new BasicNameValuePair("param2", "value2")); UrlEncodedFormEntity entity = new UrlEncodedFormEntity(formparams, Consts.UTF_8); HttpPost httppost = new HttpPost("http://localhost/handler.do"); httppost.setEntity(entity);
UrlEncodedFormEntity实例将使用所谓的URL编码来对参数和进行编码:param1=value1¶m2=value2
2)Content chunking (内容分块)
对应的Content-Type:application/octet-stream?(不确定)
用在服务器生成的消息无法确定消息大小,而进行分块加载
StringEntity entity = new StringEntity("important message", ContentType.create("plain/text", Consts.UTF_8)); entity.setChunked(true); HttpPost httppost = new HttpPost("http://localhost/acrtion.do"); httppost.setEntity(entity);
7、重试处理器
HttpRequestRetryHandler myRetryHandler = new HttpRequestRetryHandler() { @Override public boolean retryRequest(IOException exception, int executionCount, HttpContext context) { if (executionCount >= 5) { // Do not retry if over max retry count return false; } return false; } }; CloseableHttpClient httpclient = HttpClients.custom() .setRetryHandler(myRetryHandler) .build();
8、SSL/TLS
HttpClient利用SSLConnectionSocketFactory来创建SSL连接。SSLConnectionSocketFactory允许高度定制。它可以将javax.net.ssl.SSLContext的实例作为参数,并使用它创建自定义配置的SSL连接
KeyStore myTrustStore = <...> SSLContext sslContext = SSLContexts.custom() .loadTrustMaterial(myTrustStore) .build(); SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContext); CloseableHttpClient httpclient = HttpClients.custom() .setSSLSocketFactory(sslsf) .build();
9、Hostname verification
除了在SSL/TLS协议级别上执行的信任验证和客户端身份验证之外,一旦建立了连接,HttpClient还可以选择性地验证目标主机名是否与存储在服务器的X.509证书中的名称相匹配。这种验证可以为服务器信任材料的真实性提供额外的保证。hostnameverifier接口代表了一种验证主机名的策略。
重要提示:不应将hostnameverification与SSL信任验证混淆。
HttpClient附带两个javax.net.ssl.HostnameVerifier实现。
1)DefaultHostnameVerifier:主机名必须与证书指定的任何替代名称匹配,如果没有替代名称,则提供证书主体的最特定CN
2)NoopHostnameVerifier:这个主机名验证器实际上关闭了主机名验证。它接受任何有效的、与目标主机匹配的SSL会话。
每个默认的HttpClient使用DefaultHostnameVerifier实现。如果需要,可以指定不同的主机名验证器实现,如使用NoopHostnameVerifier:
SSLContext sslContext = SSLContexts.createSystemDefault(); SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory( sslContext, NoopHostnameVerifier.INSTANCE);
10、HTTP execution context 执行上下文
最初,HTTP被设计成一种无状态的、面向响应请求的协议。然而,现实世界中的应用程序通常需要能够通过几个逻辑相关的请求-响应交换来持久化状态信息。为了使应用程序能够维护一个处理状态,HttpClient允许在一个特定的执行上下文中执行HTTP请求,即HTTP上下文。如果在连续的请求之间重用相同的上下文,则多个逻辑相关的请求可以参与逻辑会话。HTTP上下文的功能类似于java.util.Map。它只是一个任意命名值的集合。应用程序可以在请求执行之前填充上下文属性,或者在执行完成后检查上下文。
HttpContext:可能包含任意对象,因此在多个线程之间共享是不安全的。建议每个执行线程维护自己的上下文。
在HTTP请求执行过程中,HttpClient将以下属性添加到执行上下文
HttpConnection | 实例表示到目标服务器的实际连接 |
HttpHost | 表示连接目标的实例 |
HttpRoute | 表示完整连接路由的实例 |
HttpRequest | 实例表示实际的HTTP请求。执行上下文中的最后一个HttpRequest对象始终表示消息发送到目标服务器时的状态。对于默认的HTTP/1.0和HTTP/1.1,使用相对请求uri。但是,如果以非隧道模式通过代理发送请求,则URI将是绝对的。 |
HttpResponse | 实例表示实际的HTTP响应 |
RequestConfig | 表示实际请求配置的对象。 |
示例:
CloseableHttpClient httpclient = HttpClients.createDefault(); try { // Create a local instance of cookie store CookieStore cookieStore = new BasicCookieStore(); // Create local HTTP context HttpClientContext localContext = HttpClientContext.create(); // Bind custom cookie store to the local context localContext.setCookieStore(cookieStore); HttpGet httpget = new HttpGet("http://httpbin.org/cookies"); System.out.println("Executing request " + httpget.getRequestLine()); // Pass local context as a parameter CloseableHttpResponse response = httpclient.execute(httpget, localContext); try { System.out.println("----------------------------------------"); System.out.println(response.getStatusLine()); List<Cookie> cookies = cookieStore.getCookies(); for (int i = 0; i < cookies.size(); i++) { System.out.println("Local cookie: " + cookies.get(i)); } EntityUtils.consume(response.getEntity()); } finally { response.close(); } } finally { httpclient.close(); }
11、设置超时时间
// 设置超时时间 RequestConfig requestConfig = RequestConfig.custom() .setSocketTimeout(5000) .setConnectTimeout(5000) .setConnectionRequestTimeout(5000) .build(); httpPost.setConfig(requestConfig);
12、中止请求:httpget.abort();
13、验证用户身份的请求
CredentialsProvider credsProvider = new BasicCredentialsProvider(); credsProvider.setCredentials( new AuthScope("httpbin.org", 80), new UsernamePasswordCredentials("user", "passwd")); CloseableHttpClient httpclient = HttpClients.custom() .setDefaultCredentialsProvider(credsProvider) .build(); ...
14、设置代理
HttpHost target = new HttpHost("httpbin.org", 443, "https");// 目标请求地址 HttpHost proxy = new HttpHost("127.0.0.1", 8080, "http");// 客户端代理 RequestConfig config = RequestConfig.custom() .setProxy(proxy) .build(); HttpGet request = new HttpGet("/"); request.setConfig(config); CloseableHttpResponse response = httpclient.execute(target, request);
15、通过身份验证代理在安全连接隧道上执行HTTP请求
CredentialsProvider credsProvider = new BasicCredentialsProvider(); credsProvider.setCredentials( new AuthScope("localhost", 8888), new UsernamePasswordCredentials("squid", "squid")); credsProvider.setCredentials( new AuthScope("httpbin.org", 80), new UsernamePasswordCredentials("user", "passwd")); CloseableHttpClient httpclient = HttpClients.custom() .setDefaultCredentialsProvider(credsProvider).build(); try { HttpHost target = new HttpHost("httpbin.org", 80, "http"); HttpHost proxy = new HttpHost("localhost", 8888); RequestConfig config = RequestConfig.custom() .setProxy(proxy) .build(); HttpGet httpget = new HttpGet("/basic-auth/user/passwd"); httpget.setConfig(config); CloseableHttpResponse response = httpclient.execute(target, httpget); try { System.out.println(EntityUtils.toString(response.getEntity())); } finally { response.close(); } } finally { httpclient.close(); }
16、使用块编码(chunk)来发送请求实体
CloseableHttpClient httpclient = HttpClients.createDefault(); try { HttpPost httppost = new HttpPost("http://httpbin.org/post"); File file = new File("filePath"); InputStreamEntity reqEntity = new InputStreamEntity( new FileInputStream(file), -1, ContentType.APPLICATION_OCTET_STREAM); reqEntity.setChunked(true); // It may be more appropriate to use FileEntity class in this particular // instance but we are using a more generic InputStreamEntity to demonstrate // the capability to stream out data from any arbitrary source // // FileEntity entity = new FileEntity(file, "binary/octet-stream"); httppost.setEntity(reqEntity); System.out.println("Executing request: " + httppost.getRequestLine()); CloseableHttpResponse response = httpclient.execute(httppost); try { System.out.println(response.getStatusLine()); System.out.println(EntityUtils.toString(response.getEntity())); } finally { response.close(); } } finally { httpclient.close(); }
17、使用HttpClient执行基于表单的登录
BasicCookieStore cookieStore = new BasicCookieStore(); CloseableHttpClient httpclient = HttpClients.custom() .setDefaultCookieStore(cookieStore) .build(); try { HttpGet httpget = new HttpGet("https://someportal/"); CloseableHttpResponse response1 = httpclient.execute(httpget); try { HttpEntity entity = response1.getEntity(); System.out.println("Login form get: " + response1.getStatusLine()); EntityUtils.consume(entity); System.out.println("Initial set of cookies:"); List<Cookie> cookies = cookieStore.getCookies(); if (cookies.isEmpty()) { System.out.println("None"); } else { for (int i = 0; i < cookies.size(); i++) { System.out.println("- " + cookies.get(i).toString()); } } } finally { response1.close(); } HttpUriRequest login = RequestBuilder.post() .setUri(new URI("https://someportal/")) .addParameter("IDToken1", "username") .addParameter("IDToken2", "password") .build(); CloseableHttpResponse response2 = httpclient.execute(login); try { HttpEntity entity = response2.getEntity(); System.out.println("Login form get: " + response2.getStatusLine()); EntityUtils.consume(entity); System.out.println("Post logon cookies:"); List<Cookie> cookies = cookieStore.getCookies(); if (cookies.isEmpty()) { System.out.println("None"); } else { for (int i = 0; i < cookies.size(); i++) { System.out.println("- " + cookies.get(i).toString()); } } } finally { response2.close(); } } finally { httpclient.close(); }
18、多个工作线程执行HTTP请求
// Create an HttpClient with the ThreadSafeClientConnManager. // This connection manager must be used if more than one thread will // be using the HttpClient. PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager(); cm.setMaxTotal(100); CloseableHttpClient httpclient = HttpClients.custom() .setConnectionManager(cm) .build(); try { // create an array of URIs to perform GETs on String[] urisToGet = { "http://hc.apache.org/", "http://hc.apache.org/httpcomponents-core-ga/", "http://hc.apache.org/httpcomponents-client-ga/", }; // create a thread for each URI GetThread[] threads = new GetThread[urisToGet.length]; for (int i = 0; i < threads.length; i++) { HttpGet httpget = new HttpGet(urisToGet[i]); threads[i] = new GetThread(httpclient, httpget, i + 1); } // start the threads for (int j = 0; j < threads.length; j++) { threads[j].start(); } // join the threads for (int j = 0; j < threads.length; j++) { threads[j].join(); } } finally { httpclient.close(); } /** * A thread that performs a GET. */ static class GetThread extends Thread { private final CloseableHttpClient httpClient; private final HttpContext context; private final HttpGet httpget; private final int id; public GetThread(CloseableHttpClient httpClient, HttpGet httpget, int id) { this.httpClient = httpClient; this.context = new BasicHttpContext(); this.httpget = httpget; this.id = id; } /** * Executes the GetMethod and prints some status information. */ @Override public void run() { try { System.out.println(id + " - about to get something from " + httpget.getURI()); CloseableHttpResponse response = httpClient.execute(httpget, context); try { System.out.println(id + " - get executed"); // get the response body as an array of bytes HttpEntity entity = response.getEntity(); if (entity != null) { byte[] bytes = EntityUtils.toByteArray(entity); System.out.println(id + " - " + bytes.length + " bytes read"); } } finally { response.close(); } } catch (Exception e) { System.out.println(id + " - error: " + e); } } }
19、执行包含多部分编码实体的请求
HttpPost httppost = new HttpPost("http://localhost:8080" + "/servlets-examples/servlet/RequestInfoExample"); FileBody bin = new FileBody(new File("filePath")); StringBody comment = new StringBody("A binary file of some kind", ContentType.TEXT_PLAIN); HttpEntity reqEntity = MultipartEntityBuilder.create() .addPart("bin", bin) .addPart("comment", comment) .build(); httppost.setEntity(reqEntity);
三、使用:
1、jar包依赖
<!--httpClient--> <dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpclient</artifactId> <version>4.5.9</version> </dependency>
2、HttpClientUtil工具类
import org.apache.http.HttpEntity; import org.apache.http.NameValuePair; import org.apache.http.client.config.RequestConfig; import org.apache.http.client.entity.UrlEncodedFormEntity; import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpPost; import org.apache.http.conn.ssl.NoopHostnameVerifier; import org.apache.http.conn.ssl.SSLConnectionSocketFactory; import org.apache.http.conn.ssl.TrustStrategy; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClients; import org.apache.http.message.BasicNameValuePair; import org.apache.http.ssl.SSLContexts; import org.apache.http.util.EntityUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.net.ssl.SSLContext; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.security.KeyManagementException; import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; import java.security.cert.CertificateException; import java.security.cert.X509Certificate; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; /** * Http工具类 * * @author yangyongjie * @date 2020/3/26 * @desc */ public class HttpClientUtil { private static final Logger LOGGER = LoggerFactory.getLogger(HttpClientUtil.class); /** * http get 请求 * * @param url * @return */ public static Map<String, Object> doGet(String url) { HashMap<String, Object> resultMap = new HashMap<String, Object>(8); resultMap.put("isOk", "ok"); // http客户端 CloseableHttpClient httpclient = HttpClients.createDefault(); // get请求 HttpGet httpget = new HttpGet(url); CloseableHttpResponse response = null; try { response = httpclient.execute(httpget); HttpEntity entity = response.getEntity(); String content; if (entity != null) { long len = entity.getContentLength(); if (len != -1 && len < 2048) { content = EntityUtils.toString(entity); } else { // Stream content out InputStream instream = entity.getContent(); try { BufferedReader br = new BufferedReader(new InputStreamReader(instream, StandardCharsets.UTF_8)); char[] buffer = new char[4096]; int length; StringBuilder sb = new StringBuilder(); while ((length = br.read(buffer)) > 0) { sb.append(new String(buffer, 0, length)); } content = sb.toString(); } finally { instream.close(); } } resultMap.put("content", content); } } catch (IOException e) { LOGGER.error("关闭response异常" + e.getMessage(), e); } finally { if (response != null) { try { response.close(); } catch (IOException e) { LOGGER.error("关闭response异常" + e.getMessage(), e); } } try { httpclient.close(); } catch (IOException e) { LOGGER.error("httpclient close exceprion:" + e.getMessage(), e); } } return resultMap; } /** * http post 请求 * * @param url * @param param * @return */ public static Map<String, Object> doPost(String url, Map<String, String> param) { HashMap<String, Object> resultMap = new HashMap<String, Object>(8); resultMap.put("isOk", "ok"); CloseableHttpClient httpclient = HttpClients.custom().build(); try { HttpPost httpPost = new HttpPost(url); // 设置超时时间 RequestConfig requestConfig = RequestConfig.custom() .setSocketTimeout(5000) .setConnectTimeout(5000) .setConnectionRequestTimeout(5000) .build(); httpPost.setConfig(requestConfig); LOGGER.info("Executing request {}", httpPost.getRequestLine()); List<NameValuePair> nvps = new ArrayList<NameValuePair>(); if (param != null) { for (Map.Entry<String, String> entry : param.entrySet()) { nvps.add(new BasicNameValuePair(entry.getKey(), entry.getValue())); } httpPost.setEntity(new UrlEncodedFormEntity(nvps)); } httpPost.addHeader("Accept-Encoding", "gzip,deflate"); CloseableHttpResponse response = httpclient.execute(httpPost); try { HttpEntity entity = response.getEntity(); LOGGER.info("response statusLine:{}", response.getStatusLine()); resultMap.put("status", response.getStatusLine().getStatusCode()); String content = EntityUtils.toString(response.getEntity(), StandardCharsets.UTF_8); resultMap.put("content", content); LOGGER.info("CONTENT={}", content); // and ensure it is fully consumed EntityUtils.consume(entity); } finally { response.close(); } } catch (Exception e) { LOGGER.error(url + "request exception:" + e.getMessage(), e); resultMap.put("isOk", "no"); return resultMap; } finally { try { httpclient.close(); } catch (IOException e) { LOGGER.error("httpclient close exceprion:" + e.getMessage(), e); } } return resultMap; } /** * 忽略证书验证的https post请求 * * @param url * @param param * @return */ public static Map<String, Object> doSSLPost(String url, Map<String, String> param) { HashMap<String, Object> resultMap = new HashMap<String, Object>(8); resultMap.put("isOk", "ok"); CloseableHttpClient httpclient; // Trust own CA and all self-signed certs SSLContext sslcontext = null; try { sslcontext = SSLContexts.custom().loadTrustMaterial(null, new TrustStrategy() { // 忽略所有证书验证 @Override public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException { return true; } }).build(); } catch (NoSuchAlgorithmException | KeyStoreException | KeyManagementException e) { LOGGER.error("sslcontext error" + e.getMessage(), e); resultMap.put("isOk", "no"); return resultMap; } // 忽略主机名验证 SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslcontext, NoopHostnameVerifier.INSTANCE); httpclient = HttpClients.custom().setSSLSocketFactory(sslsf).build(); try { HttpPost httpPost = new HttpPost(url); // 设置超时时间 RequestConfig requestConfig = RequestConfig.custom() .setSocketTimeout(5000) .setConnectTimeout(5000) .setConnectionRequestTimeout(5000) .build(); httpPost.setConfig(requestConfig); LOGGER.info("Executing request {}", httpPost.getRequestLine()); List<NameValuePair> nvps = new ArrayList<NameValuePair>(); if (param != null) { for (Map.Entry<String, String> entry : param.entrySet()) { nvps.add(new BasicNameValuePair(entry.getKey(), entry.getValue())); } httpPost.setEntity(new UrlEncodedFormEntity(nvps)); } httpPost.addHeader("Accept-Encoding", "gzip,deflate"); CloseableHttpResponse response = httpclient.execute(httpPost); try { HttpEntity entity = response.getEntity(); LOGGER.info("response statusLine:{}", response.getStatusLine()); resultMap.put("status", response.getStatusLine().getStatusCode()); String content = EntityUtils.toString(response.getEntity(), StandardCharsets.UTF_8); resultMap.put("content", content); LOGGER.info("CONTENT={}", content); // and ensure it is fully consumed EntityUtils.consume(entity); } finally { response.close(); } } catch (Exception e) { LOGGER.error(url + "request exception:" + e.getMessage(), e); resultMap.put("isOk", "no"); return resultMap; } finally { try { httpclient.close(); } catch (IOException e) { LOGGER.error("httpclient close exceprion:" + e.getMessage(), e); } } return resultMap; } }
2
package com.yang.http; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; 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.client.methods.HttpPost; import org.apache.http.entity.StringEntity; import org.apache.http.impl.client.HttpClients; import org.apache.http.util.EntityUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.slf4j.MDC; import java.io.IOException; import java.nio.charset.Charset; import java.util.HashMap; import java.util.Map; import java.util.UUID; /** * 〈一句话功能简述〉 * 〈功能详细描述〉 * * @author 17090889 * @see [相关类/方法](可选) * @since [产品/模块版本] (可选) */ public class HttpClientTemplate { private static final Logger LOGGER = LoggerFactory.getLogger(HttpClientTemplate.class); private static HttpClient httpClient; static { httpClient = HttpClients.createDefault(); } /** * 执行get请求 * * @param uri * @return */ public static Map<String, Object> executeGet(String uri) { HttpGet httpGet = new HttpGet(uri); Map<String, Object> resultMap = new HashMap<String, Object>(4); try { resultMap = httpClient.execute(httpGet, new ResponseHandler<Map<String, Object>>() { public Map<String, Object> handleResponse(HttpResponse httpResponse) throws ClientProtocolException, IOException { HttpEntity httpEntity = httpResponse.getEntity(); String result = EntityUtils.toString(httpEntity, Charset.forName("utf-8")); return JSON.parseObject(result); } }); } catch (Exception e) { LOGGER.error("执行get请求异常" + e.getMessage(), e); return null; } return resultMap; } /** * 执行post请求 * * @param uri * @return */ public static Map<String, Object> executePost(String uri, JSONObject jsonObject) { HttpPost httpPost = new HttpPost(uri); StringEntity entity = new StringEntity(jsonObject.toString(), "utf-8"); entity.setContentEncoding("UTF-8"); entity.setContentType("application/json"); httpPost.setEntity(entity); Map<String, Object> resultMap = new HashMap<String, Object>(4); try { resultMap = httpClient.execute(httpPost, new ResponseHandler<Map<String, Object>>() { public Map<String, Object> handleResponse(HttpResponse httpResponse) throws ClientProtocolException, IOException { HttpEntity httpEntity = httpResponse.getEntity(); String result = EntityUtils.toString(httpEntity, Charset.forName("utf-8")); return JSON.parseObject(result); } }); } catch (IOException e) { LOGGER.error("执行post请求异常" + e.getMessage(), e); return null; } return resultMap; } public static void main(String[] args) { MDC.put("threadId", UUID.randomUUID().toString().replaceAll("-", "")); // 没有数据再调用接口查询 String uri = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential" + "&appId=" + "wxe0e11acdb6dbccbb" + "&secret=" + "7dfb67f45b79292e3b0b969b2590a06b"; Map<String, Object> resultMap = HttpClientTemplate.executeGet(uri); LOGGER.info("getAccessToken-resultMap={}", resultMap); String errcode = String.valueOf(resultMap.get("errcode")); String accessToken = String.valueOf(resultMap.get("access_token")); String expiresIn = String.valueOf(resultMap.get("expires_in")); // 写死一个行业,其他,41 if (accessToken == null) { return; } String uri2 = "https://api.weixin.qq.com/cgi-bin/template/api_set_industry?access_token=" + accessToken; JSONObject jsonObject = new JSONObject(4); jsonObject.put("industry_id1", 1); jsonObject.put("industry_id2", "41"); Map<String, Object> resultMap2 = HttpClientTemplate.executePost(uri2, jsonObject); String errcode2 = String.valueOf(resultMap2.get("errcode")); MDC.remove("threadId"); } }
四、官方示例
/* * ==================================================================== * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Apache Software Foundation. For more * information on the Apache Software Foundation, please see * <http://www.apache.org/>. * */ package org.apache.http.examples.client; import java.net.InetAddress; import java.net.UnknownHostException; import java.nio.charset.CodingErrorAction; import java.util.Arrays; import javax.net.ssl.SSLContext; import org.apache.http.Consts; import org.apache.http.Header; import org.apache.http.HttpHost; import org.apache.http.HttpRequest; import org.apache.http.HttpResponse; import org.apache.http.ParseException; import org.apache.http.client.CookieStore; import org.apache.http.client.CredentialsProvider; import org.apache.http.client.config.AuthSchemes; import org.apache.http.client.config.CookieSpecs; import org.apache.http.client.config.RequestConfig; import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.HttpGet; import org.apache.http.client.protocol.HttpClientContext; import org.apache.http.config.ConnectionConfig; import org.apache.http.config.MessageConstraints; import org.apache.http.config.Registry; import org.apache.http.config.RegistryBuilder; import org.apache.http.config.SocketConfig; import org.apache.http.conn.DnsResolver; import org.apache.http.conn.HttpConnectionFactory; import org.apache.http.conn.ManagedHttpClientConnection; import org.apache.http.conn.routing.HttpRoute; import org.apache.http.conn.socket.ConnectionSocketFactory; import org.apache.http.conn.socket.PlainConnectionSocketFactory; import org.apache.http.conn.ssl.SSLConnectionSocketFactory; import org.apache.http.impl.DefaultHttpResponseFactory; import org.apache.http.impl.client.BasicCookieStore; import org.apache.http.impl.client.BasicCredentialsProvider; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClients; import org.apache.http.impl.conn.DefaultHttpResponseParser; import org.apache.http.impl.conn.DefaultHttpResponseParserFactory; import org.apache.http.impl.conn.ManagedHttpClientConnectionFactory; import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; import org.apache.http.impl.conn.SystemDefaultDnsResolver; import org.apache.http.impl.io.DefaultHttpRequestWriterFactory; import org.apache.http.io.HttpMessageParser; import org.apache.http.io.HttpMessageParserFactory; import org.apache.http.io.HttpMessageWriterFactory; import org.apache.http.io.SessionInputBuffer; import org.apache.http.message.BasicHeader; import org.apache.http.message.BasicLineParser; import org.apache.http.message.LineParser; import org.apache.http.ssl.SSLContexts; import org.apache.http.util.CharArrayBuffer; import org.apache.http.util.EntityUtils; /** * This example demonstrates how to customize and configure the most common aspects * of HTTP request execution and connection management. */ public class ClientConfiguration { public final static void main(String[] args) throws Exception { // Use custom message parser / writer to customize the way HTTP // messages are parsed from and written out to the data stream. HttpMessageParserFactory<HttpResponse> responseParserFactory = new DefaultHttpResponseParserFactory() { @Override public HttpMessageParser<HttpResponse> create( SessionInputBuffer buffer, MessageConstraints constraints) { LineParser lineParser = new BasicLineParser() { @Override public Header parseHeader(final CharArrayBuffer buffer) { try { return super.parseHeader(buffer); } catch (ParseException ex) { return new BasicHeader(buffer.toString(), null); } } }; return new DefaultHttpResponseParser( buffer, lineParser, DefaultHttpResponseFactory.INSTANCE, constraints) { @Override protected boolean reject(final CharArrayBuffer line, int count) { // try to ignore all garbage preceding a status line infinitely return false; } }; } }; HttpMessageWriterFactory<HttpRequest> requestWriterFactory = new DefaultHttpRequestWriterFactory(); // Use a custom connection factory to customize the process of // initialization of outgoing HTTP connections. Beside standard connection // configuration parameters HTTP connection factory can define message // parser / writer routines to be employed by individual connections. HttpConnectionFactory<HttpRoute, ManagedHttpClientConnection> connFactory = new ManagedHttpClientConnectionFactory( requestWriterFactory, responseParserFactory); // Client HTTP connection objects when fully initialized can be bound to // an arbitrary network socket. The process of network socket initialization, // its connection to a remote address and binding to a local one is controlled // by a connection socket factory. // SSL context for secure connections can be created either based on // system or application specific properties. SSLContext sslcontext = SSLContexts.createSystemDefault(); // Create a registry of custom connection socket factories for supported // protocol schemes. Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory>create() .register("http", PlainConnectionSocketFactory.INSTANCE) .register("https", new SSLConnectionSocketFactory(sslcontext)) .build(); // Use custom DNS resolver to override the system DNS resolution. DnsResolver dnsResolver = new SystemDefaultDnsResolver() { @Override public InetAddress[] resolve(final String host) throws UnknownHostException { if (host.equalsIgnoreCase("myhost")) { return new InetAddress[] { InetAddress.getByAddress(new byte[] {127, 0, 0, 1}) }; } else { return super.resolve(host); } } }; // Create a connection manager with custom configuration. PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager( socketFactoryRegistry, connFactory, dnsResolver); // Create socket configuration SocketConfig socketConfig = SocketConfig.custom() .setTcpNoDelay(true) .build(); // Configure the connection manager to use socket configuration either // by default or for a specific host. connManager.setDefaultSocketConfig(socketConfig); connManager.setSocketConfig(new HttpHost("somehost", 80), socketConfig); // Validate connections after 1 sec of inactivity connManager.setValidateAfterInactivity(1000); // Create message constraints MessageConstraints messageConstraints = MessageConstraints.custom() .setMaxHeaderCount(200) .setMaxLineLength(2000) .build(); // Create connection configuration ConnectionConfig connectionConfig = ConnectionConfig.custom() .setMalformedInputAction(CodingErrorAction.IGNORE) .setUnmappableInputAction(CodingErrorAction.IGNORE) .setCharset(Consts.UTF_8) .setMessageConstraints(messageConstraints) .build(); // Configure the connection manager to use connection configuration either // by default or for a specific host. connManager.setDefaultConnectionConfig(connectionConfig); connManager.setConnectionConfig(new HttpHost("somehost", 80), ConnectionConfig.DEFAULT); // Configure total max or per route limits for persistent connections // that can be kept in the pool or leased by the connection manager. connManager.setMaxTotal(100); connManager.setDefaultMaxPerRoute(10); connManager.setMaxPerRoute(new HttpRoute(new HttpHost("somehost", 80)), 20); // Use custom cookie store if necessary. CookieStore cookieStore = new BasicCookieStore(); // Use custom credentials provider if necessary. CredentialsProvider credentialsProvider = new BasicCredentialsProvider(); // Create global request configuration RequestConfig defaultRequestConfig = RequestConfig.custom() .setCookieSpec(CookieSpecs.DEFAULT) .setExpectContinueEnabled(true) .setTargetPreferredAuthSchemes(Arrays.asList(AuthSchemes.NTLM, AuthSchemes.DIGEST)) .setProxyPreferredAuthSchemes(Arrays.asList(AuthSchemes.BASIC)) .build(); // Create an HttpClient with the given custom dependencies and configuration. CloseableHttpClient httpclient = HttpClients.custom() .setConnectionManager(connManager) .setDefaultCookieStore(cookieStore) .setDefaultCredentialsProvider(credentialsProvider) .setProxy(new HttpHost("myproxy", 8080)) .setDefaultRequestConfig(defaultRequestConfig) .build(); try { HttpGet httpget = new HttpGet("http://httpbin.org/get"); // Request configuration can be overridden at the request level. // They will take precedence over the one set at the client level. RequestConfig requestConfig = RequestConfig.copy(defaultRequestConfig) .setSocketTimeout(5000) .setConnectTimeout(5000) .setConnectionRequestTimeout(5000) .setProxy(new HttpHost("myotherproxy", 8080)) .build(); httpget.setConfig(requestConfig); // Execution context can be customized locally. HttpClientContext context = HttpClientContext.create(); // Contextual attributes set the local context level will take // precedence over those set at the client level. context.setCookieStore(cookieStore); context.setCredentialsProvider(credentialsProvider); System.out.println("executing request " + httpget.getURI()); CloseableHttpResponse response = httpclient.execute(httpget, context); try { System.out.println("----------------------------------------"); System.out.println(response.getStatusLine()); System.out.println(EntityUtils.toString(response.getEntity())); System.out.println("----------------------------------------"); // Once the request has been executed the local context can // be used to examine updated state and various objects affected // by the request execution. // Last executed request context.getRequest(); // Execution route context.getHttpRoute(); // Target auth state context.getTargetAuthState(); // Proxy auth state context.getProxyAuthState(); // Cookie origin context.getCookieOrigin(); // Cookie spec used context.getCookieSpec(); // User security token context.getUserToken(); } finally { response.close(); } } finally { httpclient.close(); } } }
END