欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Java11新特性之HttpClient小試牛刀

 更新時(shí)間:2018年09月29日 09:37:55   作者:codecraft  
本文主要研究一下Java11的HttpClient的基本使用。小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧


本文主要研究一下Java11的HttpClient的基本使用。

變化

  1. 從java9的jdk.incubator.httpclient模塊遷移到j(luò)ava.net.http模塊,包名由jdk.incubator.http改為java.net.http
  2. 原來的諸如HttpResponse.BodyHandler.asString()方法變更為HttpResponse.BodyHandlers.ofString(),變化一為BodyHandler改為BodyHandlers,變化二為asXXX()之類的方法改為ofXXX(),由as改為of

實(shí)例

設(shè)置超時(shí)時(shí)間

 @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實(shí)例

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實(shí)例

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)

設(shè)置authenticator

 @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可以用來設(shè)置HTTP authentication,比如Basic authentication
  2. 雖然Basic authentication也可以自己設(shè)置header,不過通過authenticator省得自己去構(gòu)造header

設(shè)置header

 @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可以自己設(shè)置header

GET

同步

 @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());
 }

異步

 @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表單

 @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指定內(nèi)容是表單類型,然后通過BodyPublishers.ofString傳遞表單數(shù)據(jù),需要自己構(gòu)建表單參數(shù)

POST JSON

 @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格式

文件上傳

 @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) //要設(shè)置,否則阻塞
    .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那種現(xiàn)成的BodyInserters.fromMultipartData方法,因此這里需要自己轉(zhuǎn)換
  2. 這里使用org.apache.httpcomponents(httpclient及httpmime)的MultipartEntityBuilder構(gòu)建multipartEntity,最后通過HttpRequest.BodyPublishers.ofInputStream來傳遞內(nèi)容
  3. 這里header要指定Content-Type值為multipart/form-data以及boundary的值,否則服務(wù)端可能無法解析

文件下載

 @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來接收文件

并發(fā)請(qǐng)求

 @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,可以方便地進(jìn)行轉(zhuǎn)換、組合等操作
  • 這里使用CompletableFuture.allOf組合在一起,最后調(diào)用join等待所有future完成

錯(cuò)誤處理

 @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異步請(qǐng)求返回的是CompletableFuture<HttpResponse<T>>,其自帶exceptionally方法可以用來做fallback處理
  • 另外值得注意的是HttpClient不像WebClient那樣,它沒有對(duì)4xx或5xx的狀態(tài)碼拋出異常,需要自己根據(jù)情況來處理,手動(dòng)檢測狀態(tài)碼拋出異?;蛘叻祷仄渌麅?nèi)容

HTTP2

 @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();
 }

執(zhí)行之后可以看到返回的response的version為HTTP_2

WebSocket

 @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去構(gòu)造WebSocket
  • 傳入listener進(jìn)行接收消息,要發(fā)消息的話,使用WebSocket來發(fā)送,關(guān)閉使用sendClose方法

reactive streams

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

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的實(shí)現(xiàn)

小結(jié)

HttpClient在Java11從incubator變?yōu)檎桨?,相?duì)于傳統(tǒng)的HttpUrlConnection其提升可不是一點(diǎn)半點(diǎn),不僅支持異步,也支持reactive streams,同時(shí)也支持了HTTP2以及WebSocket,非常值得大家使用。

以上就是本文的全部內(nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • Spring AOP使用@Aspect注解 面向切面實(shí)現(xiàn)日志橫切的操作

    Spring AOP使用@Aspect注解 面向切面實(shí)現(xiàn)日志橫切的操作

    這篇文章主要介紹了Spring AOP使用@Aspect注解 面向切面實(shí)現(xiàn)日志橫切的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-06-06
  • 利用java生成二維碼工具類示例代碼

    利用java生成二維碼工具類示例代碼

    二維碼對(duì)現(xiàn)在的人們來說再熟悉不過了,我們?cè)陂_發(fā)的時(shí)候也經(jīng)常會(huì)用到二維碼,下面這篇文章主要給大家介紹了關(guān)于利用java生成二維碼工具類的相關(guān)資料,文中給了詳細(xì)的示例代碼,需要的朋友可以參考借鑒,下面來一起看看吧。
    2017-09-09
  • springboot代碼,注解配置獲取yml,properties文件的map即鍵值對(duì)

    springboot代碼,注解配置獲取yml,properties文件的map即鍵值對(duì)

    這篇文章主要介紹了springboot代碼,注解配置獲取yml,properties文件的map即鍵值對(duì),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-02-02
  • 詳細(xì)分析Java內(nèi)存模型

    詳細(xì)分析Java內(nèi)存模型

    Java虛擬機(jī)規(guī)范中定義了Java內(nèi)存模型(Java Memory Model,JMM),用于屏蔽掉各種硬件和操作系統(tǒng)的內(nèi)存訪問差異,以實(shí)現(xiàn)讓Java程序在各種平臺(tái)下都能達(dá)到一致的并發(fā)效果,JMM規(guī)范了Java虛擬機(jī)與計(jì)算機(jī)內(nèi)存是如何協(xié)同工作的,以及在必須時(shí)如何同步的訪問共享變量
    2021-06-06
  • MyBatis中多條件查詢商品的三種方法及區(qū)別

    MyBatis中多條件查詢商品的三種方法及區(qū)別

    本文主要介紹了MyBatis中多條件查詢商品的三種方法及區(qū)別,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-01-01
  • IntelliJ IDEA Run時(shí)報(bào)“無效的源發(fā)行版:16“錯(cuò)誤問題及解決方法

    IntelliJ IDEA Run時(shí)報(bào)“無效的源發(fā)行版:16“錯(cuò)誤問題及解決方法

    這篇文章主要介紹了IntelliJ IDEA Run時(shí)報(bào)“無效的源發(fā)行版:16“錯(cuò)誤問題及解決方法,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2023-05-05
  • 詳解Java中日志跟蹤的簡單實(shí)現(xiàn)

    詳解Java中日志跟蹤的簡單實(shí)現(xiàn)

    MDC?(Mapped?Diagnostic?Context,映射調(diào)試上下文)是?log4j??、logback及l(fā)og4j2??提供的一種方便在多線程條件下記錄日志的功能。本文將利用MDC實(shí)現(xiàn)簡單的日志跟蹤,需要的可以參考一下
    2022-08-08
  • mybatis中映射文件(mapper)中的使用規(guī)則

    mybatis中映射文件(mapper)中的使用規(guī)則

    這篇文章主要介紹了mybatis中映射文件(mapper)中的使用規(guī)則,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-11-11
  • 淺談Java抽象類和接口的個(gè)人理解

    淺談Java抽象類和接口的個(gè)人理解

    這篇文章主要介紹了淺談Java抽象類和接口的個(gè)人理解,具有一定借鑒價(jià)值,需要的朋友可以參考下。
    2017-12-12
  • 詳解Java如何實(shí)現(xiàn)FP-Growth算法

    詳解Java如何實(shí)現(xiàn)FP-Growth算法

    學(xué)校里的實(shí)驗(yàn),要求實(shí)現(xiàn)FP-Growth算法.FP-Growth算法比Apriori算法快很多(但是卻比不上時(shí)間)在網(wǎng)上搜索后發(fā)現(xiàn)Java實(shí)現(xiàn)的FP-Growth算法很少,且大多數(shù)不太能理解):太菜.所以就自己實(shí)現(xiàn)了一下.這篇文章重點(diǎn)介紹一下我的Java實(shí)現(xiàn) ,需要的朋友可以參考下
    2021-06-06

最新評(píng)論