JDK11新特性 --httpClient
一:HttpURLConnenction目前存在的問題
1.其基類 URLConnection 當(dāng)初是設(shè)計(jì)為支持多協(xié)議杀狡,但其中大多已經(jīng)成為非主流(ftp, gopher…)
2.API 的設(shè)計(jì)早于 HTTP/1.1然磷,過度抽象
3.難以使用,存在許多沒有文檔化的行為
4.它只支持阻塞模式(每個(gè)請(qǐng)求 / 響應(yīng)占用一個(gè)線程)
二: HttpClient簡(jiǎn)介
httpclient是Apache Jakarta common下的子項(xiàng)目谓媒,用來提供高效的饺著、最新的、更能豐富的支持http協(xié)議的客戶端編程工具包抑月,并且它支持http協(xié)議最新的版本和建議。httpclient已經(jīng)應(yīng)用在很多項(xiàng)目中舆蝴,比如Apache Jakarta上很著名的兩個(gè)開源項(xiàng)目cactus和httplunit都使用了httpclient谦絮。
三:HttpClient特性
1.以可擴(kuò)展的面向?qū)ο蟮慕Y(jié)構(gòu)實(shí)現(xiàn)了HTTP全部的方法(GET、POST洁仗、put层皱、delete、head赠潦、options奶甘、trace)。
2.支持HTTPS協(xié)議祭椰。
3.通過HTTP代理建立透明的連接臭家。
4.連接管理器支持多線程應(yīng)用。支持設(shè)置最大連接數(shù)方淤,同事支持設(shè)置每個(gè)主機(jī)的最大連接數(shù)钉赁,發(fā)現(xiàn)并關(guān)閉過期的連接。
5.自動(dòng)處理Set-Cookie中的Cookie携茂。
6.插件式的自定義Cookie策略你踩。
7.request的輸出流可以避免流中內(nèi)容直接緩沖到socket服務(wù)器。
8.Response的輸入流可以有效的從socket服務(wù)器直接讀取相應(yīng)內(nèi)容
三:使用方法
使用HttpClient發(fā)送請(qǐng)求讳苦、接收響應(yīng)很簡(jiǎn)單带膜,一般需要如下幾步即可。
1鸳谜、創(chuàng)建httpclient對(duì)象膝藕。
2、創(chuàng)建請(qǐng)求方法的實(shí)例咐扭,并制定請(qǐng)求url芭挽。如果需要發(fā)送get請(qǐng)求,創(chuàng)建httpclient對(duì)象蝗肪;如果需要發(fā)送post請(qǐng)求袜爪,創(chuàng)建httpPOST對(duì)象。
3薛闪、如果需要發(fā)送請(qǐng)求參數(shù)辛馆,可調(diào)用httpget、httpPost共同的setparams(HetpParams params)方法來添加請(qǐng)求參數(shù)豁延;對(duì)于HttpPost對(duì)象而言昙篙,也可調(diào)用setEntity(HttpEntity entity)方法來設(shè)置請(qǐng)求參數(shù)倔韭。
4、調(diào)用HttpClient對(duì)象的execute(HttpUriRequest request)發(fā)送請(qǐng)求瓢对,該方法返回一個(gè)HttpResponse寿酌。
5、調(diào)用HttpResponse的getAllHeaders()硕蛹、getHeaders(String name)等方法可獲取服務(wù)器的響應(yīng)頭醇疼;調(diào)用HttpResponse的getEntity()方法可獲取HttpEntity對(duì)象,該對(duì)象包裝了服務(wù)器的響應(yīng)內(nèi)容法焰。程序可通過該對(duì)象獲取服務(wù)器的響應(yīng)內(nèi)容秧荆。
6、釋放連接埃仪。無論執(zhí)行方法是否成功乙濒,都必須釋放連接
四:代碼實(shí)例
實(shí)例1:同步get請(qǐng)求
public void syncGet() throws InterruptedException, IOException {
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder().uri(URI.create("https://www.baidu.com")).build();
HttpResponse<String> response =
client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
}
實(shí)例2:異步Get 請(qǐng)求
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder().uri(URI.create("https://www.baidu.com")).build();
CompletableFuture<String> result = client.sendAsync(request, HttpResponse.BodyHandlers.ofString()).thenApply(HttpResponse::body);
System.out.println(result.get());
}
實(shí)例四:Post請(qǐng)求
HttpClient client = HttpClient.newBuilder().build();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("http://www.w3school.com.cn/demo/demo_form.asp"))
.header("Content-Type","application/x-www-form-urlencoded")
.POST(HttpRequest.BodyPublishers.ofString("name1=value1&name2=value2"))
.build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.statusCode());
}
實(shí)例五:JSON傳參 header指定內(nèi)容是表單類型,然后通過BodyPublishers.ofString傳遞表單數(shù)據(jù)卵蛉,需要自己構(gòu)建表單參數(shù)
ObjectMapper objectMapper = new ObjectMapper();
StockDto dto = new StockDto();
dto.setName("hj");
dto.setSymbol("hj");
dto.setType(StockDto.StockType.SH);
String requestBody = objectMapper
.writerWithDefaultPrettyPrinter()
.writeValueAsString(dto);
HttpRequest request = HttpRequest.newBuilder(URI.create("http://localhost:8080/json/demo"))
.header("Content-Type", "application/json")
.POST(HttpRequest.BodyPublishers.ofString(requestBody))
.build();
CompletableFuture<StockDto> result = HttpClient.newHttpClient()
.sendAsync(request, HttpResponse.BodyHandlers.ofString())
.thenApply(HttpResponse::body)
.thenApply(body -> {
try {
return objectMapper.readValue(body,StockDto.class);
} catch (IOException e) {
return new StockDto();
}
});StockDto
System.out.println(result.get());
實(shí)例六:并發(fā)請(qǐng)求
//endAsync方法返回的是CompletableFuture颁股,可以方便地進(jìn)行轉(zhuǎn)換、組合等操作
//這里使用CompletableFuture.allOf組合在一起傻丝,最后調(diào)用join等待所有future完成
public void testConcurrentRequests(){
HttpClient client = HttpClient.newHttpClient();
List<String> urls = List.of("http://www.baidu.com","http://www.alibaba.com/","http://www.tencent.com");
List<HttpRequest> requests = urls.stream()
.map(url -> HttpRequest.newBuilder(URI.create(url)))
.map(reqBuilder -> reqBuilder.build())
.collect(Collectors.toList());
List<CompletableFuture<HttpResponse<String>>> futures = requests.stream()
.map(request -> client.sendAsync(request, HttpResponse.BodyHandlers.ofString()))
.collect(Collectors.toList());
futures.stream()
.forEach(e -> e.whenComplete((resp,err) -> {
if(err != null){
err.printStackTrace();
}else{
System.out.println(resp.body());
System.out.println(resp.statusCode());
}
}));
CompletableFuture.allOf(futures
.toArray(CompletableFuture<?>[]::new))
.join();
}
六:總結(jié)
HttpClient中常用到的類
HttpClient
|-- DefaultHttpClient
構(gòu)造方法: DefaultHttpClient
主要方法: HttpResponse execute(HttpUriRequest request)
HttpUriRequest
|-- HttpGet
構(gòu)造方法: HttpGet()
HttpGet(String uri)
|-- HttpPost
構(gòu)造方法: HttpPost(String uri)
主要方法: void setEntity(HttpEntity entity)
HttpResponse
主要方法:
StatusLine getStatusLine()
Header[] getAllHeaders();
HttpEntity getEntity();
HttpEntity
主要方法:
InputStream getContent();
long getContentLength();
Header getContentType();
|-- UrlEncodedFormEntity
構(gòu)造方法:UrlEncodedFormEntity(List<? extends NameValuePair> params)
//用于向請(qǐng)求對(duì)象中寫入請(qǐng)求實(shí)體(包含請(qǐng)求參數(shù)(NameValuePair))
EntityUtils
public static byte[] toByteArray(HttpEntity entity)
public static String toString(HttpEntity entity)
public static String toString(HttpEntity entity , String encoding)
StatusLine
int getStatusCode()
HttpStatus
SC_OK SC_NOT_FOUND
Header
String getName()
String getValue()
NameValuePair
String getName()
String getValue()
|-- BasicNameValuePair
構(gòu)造方法:BasicNameValuePair(String name , String value)