激情久久久_欧美视频区_成人av免费_不卡视频一二三区_欧美精品在欧美一区二区少妇_欧美一区二区三区的

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術|正則表達式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務器之家 - 編程語言 - Java教程 - Java11新特性之HttpClient小試牛刀

Java11新特性之HttpClient小試牛刀

2021-06-02 13:50codecraft Java教程

本文主要研究一下Java11的HttpClient的基本使用。小編覺得挺不錯的,現在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧

本文主要研究一下java11的httpclient的基本使用。

變化

  1. 從java9的jdk.incubator.httpclient模塊遷移到java.net.http模塊,包名由jdk.incubator.http改為java.net.http
  2. 原來的諸如httpresponse.bodyhandler.asstring()方法變更為httpresponse.bodyhandlers.ofstring(),變化一為bodyhandler改為bodyhandlers,變化二為asxxx()之類的方法改為ofxxx(),由as改為of

實例

設置超時時間

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
@test
public void testtimeout() throws ioexception, interruptedexception {
 //1.set connect timeout
 httpclient client = httpclient.newbuilder()
   .connecttimeout(duration.ofmillis(5000))
   .followredirects(httpclient.redirect.normal)
   .build();
 
 //2.set read timeout
 httprequest request = httprequest.newbuilder()
   .uri(uri.create("http://openjdk.java.net/"))
   .timeout(duration.ofmillis(5009))
   .build();
 
 httpresponse<string> response =
   client.send(request, httpresponse.bodyhandlers.ofstring());
 
 system.out.println(response.body());
 
}

httpconnecttimeoutexception實例

?
1
2
3
4
5
6
7
caused by: java.net.http.httpconnecttimeoutexception: http connect timed out
 at java.net.http/jdk.internal.net.http.responsetimerevent.handle(responsetimerevent.java:68)
 at java.net.http/jdk.internal.net.http.httpclientimpl.purgetimeoutsandreturnnextdeadline(httpclientimpl.java:1248)
 at java.net.http/jdk.internal.net.http.httpclientimpl$selectormanager.run(httpclientimpl.java:877)
caused by: java.net.connectexception: http connect timed out
 at java.net.http/jdk.internal.net.http.responsetimerevent.handle(responsetimerevent.java:69)
 ... 2 more

httptimeoutexception實例

?
1
2
3
4
5
java.net.http.httptimeoutexception: request timed out
 
 at java.net.http/jdk.internal.net.http.httpclientimpl.send(httpclientimpl.java:559)
 at java.net.http/jdk.internal.net.http.httpclientfacade.send(httpclientfacade.java:119)
 at com.example.httpclienttest.testtimeout(httpclienttest.java:40)

設置authenticator

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
@test
public void testbasicauth() throws ioexception, interruptedexception {
 httpclient client = httpclient.newbuilder()
   .connecttimeout(duration.ofmillis(5000))
   .authenticator(new authenticator() {
    @override
    protected passwordauthentication getpasswordauthentication() {
     return new passwordauthentication("admin","password".tochararray());
    }
   })
   .build();
 
 httprequest request = httprequest.newbuilder()
   .uri(uri.create("http://localhost:8080/json/info"))
   .timeout(duration.ofmillis(5009))
   .build();
 
 httpresponse<string> response =
   client.send(request, httpresponse.bodyhandlers.ofstring());
 
 system.out.println(response.statuscode());
 system.out.println(response.body());
}
  1. authenticator可以用來設置http authentication,比如basic authentication
  2. 雖然basic authentication也可以自己設置header,不過通過authenticator省得自己去構造header

設置header

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@test
public void testcookies() throws ioexception, interruptedexception {
 httpclient client = httpclient.newbuilder()
   .connecttimeout(duration.ofmillis(5000))
   .build();
 httprequest request = httprequest.newbuilder()
   .uri(uri.create("http://localhost:8080/json/cookie"))
   .header("cookie","jsessionid=4f994730-32d7-4e22-a18b-25667ddeb636; userid=java11")
   .timeout(duration.ofmillis(5009))
   .build();
 httpresponse<string> response =
   client.send(request, httpresponse.bodyhandlers.ofstring());
 
 system.out.println(response.statuscode());
 system.out.println(response.body());
}

通過request可以自己設置header

get

同步

?
1
2
3
4
5
6
7
8
9
10
11
12
@test
public void testsyncget() throws ioexception, interruptedexception {
 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());
}

異步

?
1
2
3
4
5
6
7
8
9
10
11
@test
public void testasyncget() throws executionexception, interruptedexception {
 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());
}

post表單

?
1
2
3
4
5
6
7
8
9
10
11
12
@test
public void testpostform() throws ioexception, interruptedexception {
 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());
}

header指定內容是表單類型,然后通過bodypublishers.ofstring傳遞表單數據,需要自己構建表單參數

post json

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
@test
public void testpostjsongetjson() throws executionexception, interruptedexception, jsonprocessingexception {
 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();
    }
   });
 system.out.println(result.get());
}

post json的話,body自己json化為string,然后header指定是json格式

文件上傳

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
@test
public void testuploadfile() throws ioexception, interruptedexception, urisyntaxexception {
 httpclient client = httpclient.newhttpclient();
 path path = path.of(getclass().getclassloader().getresource("body.txt").touri());
 file file = path.tofile();
 
 string multipartformdataboundary = "java11httpclientformboundary";
 org.apache.http.httpentity multipartentity = multipartentitybuilder.create()
   .addpart("file", new filebody(file, contenttype.default_binary))
   .setboundary(multipartformdataboundary) //要設置,否則阻塞
   .build();
 
 httprequest request = httprequest.newbuilder()
   .uri(uri.create("http://localhost:8080/file/upload"))
   .header("content-type", "multipart/form-data; boundary=" + multipartformdataboundary)
   .post(httprequest.bodypublishers.ofinputstream(() -> {
    try {
     return multipartentity.getcontent();
    } catch (ioexception e) {
     e.printstacktrace();
     throw new runtimeexception(e);
    }
   }))
   .build();
 
 httpresponse<string> response =
   client.send(request, httpresponse.bodyhandlers.ofstring());
 
 system.out.println(response.body());
}
  1. 官方的httpclient并沒有提供類似webclient那種現成的bodyinserters.frommultipartdata方法,因此這里需要自己轉換
  2. 這里使用org.apache.httpcomponents(httpclient及httpmime)的multipartentitybuilder構建multipartentity,最后通過httprequest.bodypublishers.ofinputstream來傳遞內容
  3. 這里header要指定content-type值為multipart/form-data以及boundary的值,否則服務端可能無法解析

文件下載

?
1
2
3
4
5
6
7
8
9
10
11
@test
public void testasyncdownload() throws executionexception, interruptedexception {
 httpclient client = httpclient.newhttpclient();
 httprequest request = httprequest.newbuilder()
   .uri(uri.create("http://localhost:8080/file/download"))
   .build();
 
 completablefuture<path> result = client.sendasync(request, httpresponse.bodyhandlers.offile(paths.get("/tmp/body.txt")))
   .thenapply(httpresponse::body);
 system.out.println(result.get());
}

使用httpresponse.bodyhandlers.offile來接收文件

并發請求

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
@test
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();
}
  • sendasync方法返回的是completablefuture,可以方便地進行轉換、組合等操作
  • 這里使用completablefuture.allof組合在一起,最后調用join等待所有future完成

錯誤處理

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
@test
 public void testhandleexception() throws executionexception, interruptedexception {
  httpclient client = httpclient.newbuilder()
    .connecttimeout(duration.ofmillis(5000))
    .build();
  httprequest request = httprequest.newbuilder()
    .uri(uri.create("https://twitter.com"))
    .build();
 
  completablefuture<string> result = client.sendasync(request, httpresponse.bodyhandlers.ofstring())
//    .whencomplete((resp,err) -> {
//     if(err != null){
//      err.printstacktrace();
//     }else{
//      system.out.println(resp.body());
//      system.out.println(resp.statuscode());
//     }
//    })
    .thenapply(httpresponse::body)
    .exceptionally(err -> {
     err.printstacktrace();
     return "fallback";
    });
  system.out.println(result.get());
 }
  • httpclient異步請求返回的是completablefuture<httpresponse<t>>,其自帶exceptionally方法可以用來做fallback處理
  • 另外值得注意的是httpclient不像webclient那樣,它沒有對4xx或5xx的狀態碼拋出異常,需要自己根據情況來處理,手動檢測狀態碼拋出異常或者返回其他內容

http2

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
@test
public void testhttp2() throws urisyntaxexception {
 httpclient.newbuilder()
   .followredirects(httpclient.redirect.never)
   .version(httpclient.version.http_2)
   .build()
   .sendasync(httprequest.newbuilder()
       .uri(new uri("https://http2.akamai.com/demo"))
       .get()
       .build(),
     httpresponse.bodyhandlers.ofstring())
   .whencomplete((resp,t) -> {
    if(t != null){
     t.printstacktrace();
    }else{
     system.out.println(resp.version());
     system.out.println(resp.statuscode());
    }
   }).join();
}

執行之后可以看到返回的response的version為http_2

websocket

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
@test
public void testwebsocket() throws interruptedexception {
 httpclient client = httpclient.newhttpclient();
 websocket websocket = client.newwebsocketbuilder()
   .buildasync(uri.create("ws://localhost:8080/echo"), new websocket.listener() {
 
    @override
    public completionstage<?> ontext(websocket websocket, charsequence data, boolean last) {
     // request one more
     websocket.request(1);
 
     // print the message when it's available
     return completablefuture.completedfuture(data)
       .thenaccept(system.out::println);
    }
   }).join();
 websocket.sendtext("hello ", false);
 websocket.sendtext("world ",true);
 
 timeunit.seconds.sleep(10);
 websocket.sendclose(websocket.normal_closure, "ok").join();
}
  • httpclient支持http2,也包含了websocket,通過newwebsocketbuilder去構造websocket
  • 傳入listener進行接收消息,要發消息的話,使用websocket來發送,關閉使用sendclose方法

reactive streams

httpclient本身就是reactive的,支持reactive streams,這里舉responsesubscribers.bytearraysubscriber的源碼看看:
java.net.http/jdk/internal/net/http/responsesubscribers.java

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
public static class bytearraysubscriber<t> implements bodysubscriber<t> {
  private final function<byte[], t> finisher;
  private final completablefuture<t> result = new minimalfuture<>();
  private final list<bytebuffer> received = new arraylist<>();
 
  private volatile flow.subscription subscription;
 
  public bytearraysubscriber(function<byte[],t> finisher) {
   this.finisher = finisher;
  }
 
  @override
  public void onsubscribe(flow.subscription subscription) {
   if (this.subscription != null) {
    subscription.cancel();
    return;
   }
   this.subscription = subscription;
   // we can handle whatever you've got
   subscription.request(long.max_value);
  }
 
  @override
  public void onnext(list<bytebuffer> items) {
   // incoming buffers are allocated by http client internally,
   // and won't be used anywhere except this place.
   // so it's free simply to store them for further processing.
   assert utils.hasremaining(items);
   received.addall(items);
  }
 
  @override
  public void onerror(throwable throwable) {
   received.clear();
   result.completeexceptionally(throwable);
  }
 
  static private byte[] join(list<bytebuffer> bytes) {
   int size = utils.remaining(bytes, integer.max_value);
   byte[] res = new byte[size];
   int from = 0;
   for (bytebuffer b : bytes) {
    int l = b.remaining();
    b.get(res, from, l);
    from += l;
   }
   return res;
  }
 
  @override
  public void oncomplete() {
   try {
    result.complete(finisher.apply(join(received)));
    received.clear();
   } catch (illegalargumentexception e) {
    result.completeexceptionally(e);
   }
  }
 
  @override
  public completionstage<t> getbody() {
   return result;
  }
 }
  1. bodysubscriber接口繼承了flow.subscriber<list<bytebuffer>>接口
  2. 這里的subscription來自flow類,該類是java9引入的,里頭包含了支持reactive streams的實現

小結

httpclient在java11從incubator變為正式版,相對于傳統的httpurlconnection其提升可不是一點半點,不僅支持異步,也支持reactive streams,同時也支持了http2以及websocket,非常值得大家使用。

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持服務器之家。

原文鏈接:https://segmentfault.com/a/1190000016555671

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 欧美在线观看黄色 | 久久精品视频3 | 黄色网址免费在线播放 | 羞羞视频免费观看入口 | 欧美爱爱视频免费看 | 成年人网站视频免费 | 在线观看免费视频麻豆 | 亚洲第一成人在线 | 国产精品亚洲欧美 | 国产精品毛片va一区二区三区 | 中午字幕无线码一区2020 | 精品国产一区二区三区久久久蜜 | caoporn国产一区二区 | 国产青草视频在线观看视频 | 欧洲黄色一级视频 | 91精品国产一区二区三区四区在线 | 免费激情视频网站 | 在线视频成人永久免费 | 看免费黄色大片 | 一本一道久久久a久久久精品91 | 日本在线不卡免费 | 欧美亚洲免费 | 精品一区二区三区免费看 | 欧美极品欧美精品欧美视频 | 中国fx性欧美xxxx | 中文字幕在线网 | 黑人一级片视频 | 久草在线手机视频 | 欧美精品一区二区三区久久久 | 亚洲人成综合第一网 | 国产一精品久久99无吗一高潮 | 91 久久 | 免费啪啪 | 国产精品一区在线免费观看 | 国产欧美在线观看不卡一 | 欧美日韩亚洲一区二区三区 | 萌白酱福利视频在线网站 | 无码专区aaaaaa免费视频 | 欧美18一19sex性护士农村 | 久久久久二区 | av国产片|