工具篇:apache-httpClient 和 jdk11-HttpClient的使用
阿新 • • 發佈:2021-11-13
關注公眾號,一起交流,微信搜一搜: 潛行前行
HttpClient (apache)
apache HttpClient 是 java專案裡 較為常用的元件之一;對接外部服務時,各個商家提供的介面是各式各樣的,有自己的要求,因此要定製對應的請求客戶端。httpClient是一個不錯的選擇
- apache HttpClient 實現了 HTTP 1.0 和 HTTP 1.1。支援 HTTP 全部的方法(GET, POST, PUT, DELETE, HEAD, OPTIONS, and TRACE)
- GET, POST 的實現是繼承 HttpRequestBase,HttpRequestBase 實現 HttpUriRequest,HttpUriRequest 繼承 HttpRequest;GET, POST 方法對應 java 類的 HttpGet 和 HttpPost
- 支援 TLS,SSL 的 HTTPS。支援多執行緒操作
- 基於阻塞的 I/0 實現,也就是說使用 HttpClient 的執行緒會被阻塞
- 頭部資訊設定
HttpPost httpPost = new HttpPost("https://api.mch.weixin.qq.com/v3/pay/transactions/app");
httpPost.addHeader("Accept", "application/json");
httpPost.addHeader("Content-type","application/json; charset=utf-8");
- 證書資訊設定
private static SSLContext getSslContext() throws Exception { //自身私鑰 KeyStore identityKeyStore = KeyStore.getInstance("jks"); FileInputStream identityKeyStoreFile = new FileInputStream("/root/myServer.jks"); identityKeyStore.load(identityKeyStoreFile, "password1".toCharArray()); //服務端信任證書 KeyStore trustKeyStore = KeyStore.getInstance("jks"); FileInputStream trustKeyStoreFile = new FileInputStream("/root/trustKeyStore.jks"); trustKeyStore.load(trustKeyStoreFile, "password".toCharArray()); //構建SSLContexts return SSLContexts.custom() .loadKeyMaterial(identityKeyStore, "password1".toCharArray()) // load identity keystore .loadTrustMaterial(trustKeyStore, null) // load trust keystore .build(); } public static void postWithSSL(String url, String jsonBody) throws Exception { SSLContext sslContext = getSslContext(); SSLConnectionSocketFactory sslConnectionSocketFactory = new SSLConnectionSocketFactory( sslContext, new String[]{"TLSv1.2", "TLSv1.1", "TLSv1"}, null, SSLConnectionSocketFactory.getDefaultHostnameVerifier()); CloseableHttpClient client = HttpClients.custom() .setSSLSocketFactory(sslConnectionSocketFactory) .build(); /** // HttpClients 產生的 client 都共用相同的證書祕鑰 Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory>create() .register("http", PlainConnectionSocketFactory.INSTANCE) .register("https", new SSLConnectionSocketFactory(sslcontext)) .build(); HttpClients.custom().setConnectionManager(connManager); */ .... }
- 快取 cookie 設定
//自定義 cookie CookieStore cookieStore = new BasicCookieStore(); BasicClientCookie cookie = new BasicClientCookie("csc", "lwl"); cookieStore.addCookie(cookie); // 從上一次請求獲取 HttpPost httppost = ... DefaultHttpClienthttpclient = newDefaultHttpClient(); HttpResponseresponse = httpclient.execute(httppost); CookieStorecookiestore=httpclient.getCookieStore(); // DefaultHttpClient 使用 cookie HttpPost httppost2 = ... DefaultHttpClienthttpclient2 = newDefaultHttpClient(); httpclient2.setCookieStore(cookiestore); response = httpclient2.execute(httppost2);
- RequestConfig 的使用
RequestConfig defaultRequestConfig = RequestConfig.custom()
.setConnectTimeout(5000)
.setSocketTimeout(5000)
.setConnectionRequestTimeout(5000)
.setRedirectsEnabled(true)
.build();
//使用
CloseableHttpClient httpclient = HttpClients.custom()
.setDefaultRequestConfig(defaultRequestConfig)
.build();
- HttpEntity 是對《請求或者響應》物件的封裝,具體實現類有
- BasicHttpEntity,InputStreamEntity:操作物件是資料流
- BufferedHttpEntity:帶緩衝區的 HttpEntity,其他HttpEntity的包裝類,將內容存入一快取區 可以重複讀
- FileEntity:檔案對應的Entity
FileEntity entity = new FileEntity(new File(""), "application/java-achive");
- StringEntity:字串 Entity。一般用 json ,text/plain,text/xml 型別的post請求
- UrlEncodedFormEntity,一般用於 application/x-www-form-urlencoded 型別的post請求
- HttpContext:它是 Http 請求上下文類,如果是同一個上下文,則兩次請求間可以共享這個上線文的資訊。雖然 HttpClient 本身就具備維護cookies的功能,但 HttpContext 的好處是在於多個 HttpClient 例項之間可以共享 HttpContext
一些建議
- 1 釋放資源:讀取完響應後,我們需要儘快釋放response本身和響應實體本身的流來對資源進行回收
- 2 有時可能需要多次讀取返回的響應內容,將響應內容進行緩衝。最簡單的方法是用BufferedHttpEntity 類包裝原始實體。這會讓原始實體的內容被讀入記憶體緩衝區
CloseableHttpResponse response = ...
HttpEntity entity = new BufferedHttpEntity(response.getEntity());
- 3 HttpClient 的執行緒安全:使用同一個HttpClient的例項即可做到執行緒安全,因為 HttpClient 內部就有一個池化機制,支援多執行緒
- 4 EntityUtils.toString(entity) : 把內容轉成字串
CloseableHttpClient 是 HttpClient 的子類。mvn 引入
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.5</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpmime</artifactId>
<version>4.5.5</version>
</dependency>
HttpClient 的API
HttpResponse execute(HttpUriRequest request)
HttpResponse execute(HttpUriRequest request, HttpContext context)
HttpResponse execute(HttpHost target, HttpRequest request)
HttpResponse execute(HttpHost target, HttpRequest request, HttpContext context)
<T> T execute(HttpUriRequest request, ResponseHandler<? extends T> responseHandler)
<T> T execute(HttpHost target,HttpRequest request, ResponseHandler<? extends T> responseHandler)
<T> T execute(HttpHost target, HttpRequest request,
ResponseHandler<? extends T> responseHandler, HttpContext context)
get 請求
CloseableHttpClient httpclient = HttpClients.createDefault();
HttpGet httpGet = new HttpGet("http://localhost:8080/content/lwl");
CloseableHttpResponse httpResponse = httpClient.execute(httpGet);
HttpEntity httpEntity = httpResponse.getEntity();
System.out.println(EntityUtils.toString(httpEntity));// 輸出請求結果
httpResponse.close();
post 請求
CloseableHttpClient httpclient = HttpClients.createDefault();
HttpPost httpPost = new HttpPost("https://www.baidu.com");
ArrayList<NameValuePair> params = new ArrayList<NameValuePair>();
params.add(new BasicNameValuePair("username", "csc"));
params.add(new BasicNameValuePair("password", "lwl"));
httpPost.setEntity(new UrlEncodedFormEntity(params));
CloseableHttpResponse httpResponse = httpClient.execute(httpPost);
HttpEntity httpEntity = httpResponse.getEntity();
System.out.println(EntityUtils.toString(httpEntity));// 輸出請求結果
httpResponse.close();
檔案上傳
CloseableHttpClient httpClient = HttpClientBuilder.create().build();
HttpPost httpPost = new HttpPost("http://localhost:8080/lwl/upload");
MultipartEntityBuilder multipartEntityBuilder = MultipartEntityBuilder.create();
File file1 = new File("C:\\Users\\csc\\Desktop\\data.jpg"); // 第一個檔案
multipartEntityBuilder.addBinaryBody("files", file1);
File file2 = new File("C:\\Users\\csc\\Desktop\\頭像.jpg"); // 第二個檔案
// 為避免中文亂碼問題,可以對檔名 urlDecode
multipartEntityBuilder.addBinaryBody("files", file2, ContentType.DEFAULT_BINARY, URLEncoder.encode(file2.getName(), "utf-8"));
// 其它引數
multipartEntityBuilder.addTextBody("name", "lwl", ContentType.create("text/plain", Charset.forName("UTF-8")));
HttpEntity httpEntity = multipartEntityBuilder.build();
httpPost.setEntity(httpEntity);
CloseableHttpResponse response = httpClient.execute(httpPost);
HttpEntity responseEntity = response.getEntity();
System.out.println(response.getStatusLine());
response.close();
HttpClient (jdk11)
java.net.http.HttpClient 是 jdk11 中正式啟用的一個 http 工具類(在 jdk9 的時候就已經存在),官方想要取代 HttpURLConnection 和 Apache HttpClient 等比較古老的開發工具
HttpClient 的API
//建立一個 HttpClient
public static Builder newBuilder()
public static HttpClient newHttpClient() // HttpClient.newBuilder().build()
//webSocket協議的請求客戶端的構建者
public WebSocket.Builder newWebSocketBuilder()
public abstract Optional<CookieHandler> cookieHandler() // 獲取 CookieHandler
public abstract Optional<Duration> connectTimeout()
public abstract Redirect followRedirects()
public abstract Optional<ProxySelector> proxy()
public abstract SSLContext sslContext()
public abstract Optional<Executor> executor()
- HttpClient.Builder 的 API
//快取cookie設定
public Builder cookieHandler(CookieHandler cookieHandler);
//連線超時時間
public Builder connectTimeout(Duration duration);
// 證書資訊設定
public Builder sslContext(SSLContext sslContext);
// SSL / TLS / DTLS連線的引數 設定
public Builder sslParameters(SSLParameters sslParameters);
//涉及到非同步操作用到的 執行緒池
public Builder executor(Executor executor);
// 是否支援重定向 Redirect.SAME_PROTOCOL
public Builder followRedirects(Redirect policy);
// 協議版本,HTTP/1.1 還是 HTTP/2
public Builder version(HttpClient.Version version);
public Builder priority(int priority);
//配置代理
public Builder proxy(ProxySelector proxySelector);
//認證 Authenticator.getDefault()
public Builder authenticator(Authenticator authenticator);
- HttpClient 呼叫 API
//阻塞呼叫
<T> HttpResponse<T> send(HttpRequest request, HttpResponse.BodyHandler<T> responseBodyHandler)
//相當於使用了多路複用I/O
<T> CompletableFuture<HttpResponse<T>> sendAsync(HttpRequest request, BodyHandler<T> responseBodyHandler)
abstract <T> CompletableFuture<HttpResponse<T>> sendAsync(HttpRequest request,
BodyHandler<T> responseBodyHandler, PushPromiseHandler<T> pushPromiseHandler)
HttpRequest 構建的 API
對於請求內容可以使用 BodyPublishers 封裝的函式生成
HttpResponse 的API
對於響應的解析讀取可以使用 BodyHandlers 或者 BodySubscribers 封裝的函式處理
get 請求
HttpRequest request = HttpRequest.newBuilder(URI.create("http://localhost:8080/content/lwl"))
.GET()
.timeout(Duration.ofSeconds(10)) // 設定響應超時時間
.build();
HttpClient httpClient = HttpClient.newHttpClient();
HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
post 請求
String data = .....// json 請求資料
HttpRequest request = HttpRequest.newBuilder(URI.create("https://www.baidu.com"))
.POST(HttpRequest.BodyPublishers.ofString(data, Charset.defaultCharset()))
.header("Content-Type", "application/json") //設定頭部資訊
.timeout(Duration.ofSeconds(10)) // 設定響應超時時間
.build();
HttpClient httpClient = HttpClient.newHttpClient();
HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());