Detailed explanation of web client usage in spring 5

preface

Spring 5 brings a new responsive web development framework Webflux and a new httpclient framework webclient. Webclient is a non blocking, reactive client that executes HTTP requests introduced in spring 5. It has good support for synchronous, asynchronous and streaming schemes. After the webclient is released, the resttemplate will be discarded in future versions, and major new functions will not be added forward.

Comparison between webclient and resttemplate

Webclient is a fully functional HTTP request client. Compared with resttemplate, webclient supports the following:

HTTP underlying library selection

Spring 5's webclient client and Webflux server both rely on the same non blocking codec to encode and decode request and response content. By default, the underlying layer uses netty, and the built-in support of jetty reactive httpclient implementation. At the same time, the clienthttpconnector interface can also be implemented by coding to customize the new underlying library; To switch jetty implementation:

    WebClient.builder()
        .clientConnector(new JettyClientHttpConnector())
        .build();

Webclient configuration

Basic configuration

The webclient instance constructor can set some basic global web request configuration information, such as default cookie, header, baseurl, etc

WebClient.builder()
        .defaultCookie("kl","kl")
        .defaultUriVariables(ImmutableMap.of("name","kl"))
        .defaultHeader("header","kl")
        .defaultHeaders(httpHeaders -> {
          httpHeaders.add("header1","kl");
          httpHeaders.add("header2","kl");
        })
        .defaultCookies(cookie ->{
          cookie.add("cookie1","kl");
          cookie.add("cookie2","kl");
        })
        .baseUrl("http://www.kailing.pub")
        .build();

Netty library configuration

By customizing the nety underlying library, you can configure SSL secure connection, request timeout, read-write timeout, etc

    HttpClient httpClient = HttpClient.create()
        .secure(sslContextSpec -> {
          SslContextBuilder sslContextBuilder = SslContextBuilder.forClient()
              .trustManager(new File("E://server.truststore"));
          sslContextSpec.sslContext(sslContextBuilder);
        }).tcpConfiguration(tcpClient -> {
          tcpClient.doOnConnected(connection ->
              //读写超时设置
              connection.addHandlerLast(new ReadTimeoutHandler(10,TimeUnit.SECONDS))
                  .addHandlerLast(new WriteTimeoutHandler(10))
          );
          //连接超时设置
          tcpClient.option(ChannelOption.CONNECT_TIMEOUT_MILLIS,10000)
          .option(ChannelOption.TCP_NODELAY,true);
          return tcpClient;
        });

    WebClient.builder()
        .clientConnector(new ReactorClientHttpConnector(httpClient))
        .build();

Codec configuration

For specific data interaction formats, you can set custom encoding and decoding modes as follows:

    ExchangeStrategies strategies = ExchangeStrategies.builder()
        .codecs(configurer -> {
          configurer.customCodecs().decoder(new Jackson2JsonDecoder());
          configurer.customCodecs().encoder(new Jackson2JsonEncoder());
        })
        .build();
    WebClient.builder()
        .exchangeStrategies(strategies)
        .build();

Get request example

Attribute placeholders are supported during URI construction, and the real parameters can be sorted when entering parameters. At the same time, you can set the media type and encoding through accept. The final result value is received through mono and flux, and the return value is subscribed in the subscribe method.

    WebClient client = WebClient.create("http://www.kailing.pub");
    Mono<String> result = client.get()
        .uri("/article/index/arcid/{id}.html",256)
        .attributes(attr -> {
          attr.put("name","kl");
          attr.put("age","28");
        })
        .acceptCharset(StandardCharsets.UTF_8)
        .accept(MediaType.TEXT_HTML)
        .retrieve()
        .bodyToMono(String.class);
    result.subscribe(System.err::println);

Post request example

The post request example demonstrates a complex scenario that contains both form parameters and file flow data. If it is a normal post request, you can directly set the object instance through bodyvalue. The forminserter construct is not used.

    WebClient client = WebClient.create("http://www.kailing.pub");
    FormInserter formInserter = fromMultipartData("name","kl")
        .with("age",19)
        .with("map",ImmutableMap.of("xx","xx"))
        .with("file",new File("E://xxx.doc"));
    Mono<String> result = client.post()
        .uri("/article/index/arcid/{id}.html",256)
        .contentType(MediaType.APPLICATION_JSON)
        .body(formInserter)
        //.bodyValue(ImmutableMap.of("name","kl"))
        .retrieve()
        .bodyToMono(String.class);
    result.subscribe(System.err::println);

Synchronous return results

The above demonstration is asynchronous. Subscribe to the response value through mono's subscribe. Of course, if you want to get the results of synchronous blocking, you can also use Block() blocks the current thread from getting the return value.

   WebClient client = WebClient.create("http://www.kailing.pub");
   String result = client .get()
        .uri("/article/index/arcid/{id}.html",256)
        .retrieve()
        .bodyToMono(String.class)
        .block();
    System.err.println(result);

However, if multiple calls are required, it is more efficient to avoid blocking each response separately and wait for the combined results, such as:

   WebClient client = WebClient.create("http://www.kailing.pub");
    Mono<String> result1Mono = client .get()
        .uri("/article/index/arcid/{id}.html",255)
        .retrieve()
        .bodyToMono(String.class);
    Mono<String> result2Mono = client .get()
        .uri("/article/index/arcid/{id}.html",254)
        .retrieve()
        .bodyToMono(String.class);
    Map<String,String> map = Mono.zip(result1Mono,result2Mono,(result1,result2) -> {
      Map<String,String> arrayList = new HashMap<>();
      arrayList.put("result1",result1);
      arrayList.put("result2",result2);
      return arrayList;
    }).block();
    System.err.println(map.toString());

Filter filter

You can uniformly modify the interception request by setting the filter interceptor, such as the authentication scenario. For example, the filter registers a single interceptor, and the filters can register multiple interceptors. Basic authentication is the built-in interceptor for basic auth, and limitresponsesize is the built-in interceptor for limiting the size of response bytes

    WebClient.builder()
        .baseUrl("http://www.kailing.pub")
        .filter((request,next) -> {
          ClientRequest filtered = ClientRequest.from(request)
              .header("foo","bar")
              .build();
          return next.exchange(filtered);
        })
        .filters(filters ->{
          filters.add(ExchangeFilterFunctions.basicAuthentication("username","password"));
          filters.add(ExchangeFilterFunctions.limitResponseSize(800));
        })
        .build().get()
        .uri("/article/index/arcid/{id}.html",254)
        .retrieve()
        .bodyToMono(String.class)
        .subscribe(System.err::println);

Websocket support

Webclient does not support websocket requests. Websocketclient needs to be used when requesting websocket interfaces, such as:

WebSocketClient client = new ReactorNettyWebSocketClient();
URI url = new URI("ws://localhost:8080/path");
client.execute(url,session ->
    session.receive()
        .doOnNext(System.out::println)
        .then());

epilogue

We have used webclient in many projects such as business API gateway and SMS platform. From the traffic and stability of the gateway, we can see the performance and stability of webclient. The responsive programming model is the trend of web programming in the future. Resttemplate will be banned and eliminated gradually, and the official is no longer updated and maintained. Webclient well supports the responsive model and has friendly API design. It is the main force of bloggers to recommend a new httpclient library. Give it a try.

Well, the above is the whole content of this article. I hope the content of this article has a certain reference value for your study or work. Thank you for your support.

The content of this article comes from the network collection of netizens. It is used as a learning reference. The copyright belongs to the original author.
THE END
分享
二维码
< <上一篇
下一篇>>