Vår 5 WebClient

1. Oversikt

I denne opplæringen skal vi undersøke WebClient, som er en reaktiv nettklient introdusert våren 5.

Vi skal også se på WebTestClient, en WebClient designet for å brukes i tester.

2. Hva er WebClient?

For å si det enkelt, WebClient er et grensesnitt som representerer hovedinngangspunktet for å utføre nettforespørsler.

Den ble opprettet som en del av Spring Web Reactive-modulen, og skal erstatte klassikeren RestTemplate i disse scenariene. I tillegg er den nye klienten en reaktiv, ikke-blokkerende løsning som fungerer over HTTP / 1.1-protokollen.

Endelig har grensesnittet en enkelt implementering, StandardWebClient klasse, som vi skal jobbe med.

3. Avhengigheter

Siden vi bruker en Spring Boot-applikasjon, trenger vi spring-boot-starter-webflux avhengighet, samt Reactor-prosjektet.

3.1. Bygge med Maven

La oss legge til følgende avhengigheter til pom.xml fil:

 org.springframework.boot spring-boot-starter-webflux org.projectreactor reactor-spring 1.0.1.RELEASE 

3.2. Bygge med Gradle

Med Gradle må vi legge til følgende oppføringer i build.gradle fil:

avhengigheter {kompilere 'org.springframework.boot: spring-boot-starter-webflux' compile 'org.projectreactor: reactor-spring: 1.0.1. RELEASE'}

4. Arbeide med WebClient

For å jobbe ordentlig med klienten, må vi vite hvordan vi kan:

  • opprette en forekomst
  • Send en forespørsel
  • håndtere responsen

4.1. Opprette en WebClient Forekomst

Det er tre alternativer å velge mellom. Den første er å lage en WebClient objekt med standardinnstillinger:

WebClient client1 = WebClient.create (); 

Det andre alternativet er å starte en WebClient forekomst med en gitt base-URI:

WebClient client2 = WebClient.create ("// localhost: 8080"); 

Det tredje alternativet (og det mest avanserte) er å bygge en klient ved å bruke StandardWebClientBuilder klasse, som tillater full tilpasning:

WebClient client3 = WebClient .builder () .baseUrl ("// localhost: 8080"). DefaultCookie ("cookieKey", "cookieValue") .defaultHeader (HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUEValueVariue) .default. "," // localhost: 8080 ")) .build ();

4.2. Opprette en WebClient Forekomst med tidsavbrudd

Ofte er standard HTTP-tidsavbrudd på 30 sekunder for sakte for våre behov, så la oss se hvordan vi konfigurerer dem for våre WebClient forekomst.

Kjerneklassen vi bruker er TcpClient.

Der kan vi angi tidsavbrudd for tilkobling via ChannelOption.CONNECT_TIMEOUT_MILLIS verdi. Vi kan også angi tidsavbrudd for lese og skrive ved hjelp av a ReadTimeoutHandler og en WriteTimeoutHandler, henholdsvis:

TcpClient tcpClient = TcpClient .create () .option (ChannelOption.CONNECT_TIMEOUT_MILLIS, 5000). DoOnConnected (connection -> {connection.addHandlerLast (new ReadTimeoutHandler (5000, TimeUnit.MILLISECONDS)); connection.addHandler MILLISEKONDER));}); WebClient-klient = WebClient.builder () .clientConnector (ny ReactorClientHttpConnector (HttpClient.from (tcpClient))) .build ();

Noter det mens vi kan ringe pause på vår klientforespørsel også, er dette en signal timeout, ikke en HTTP-tilkobling, eller lese / skrive timeout; det er en timeout for Mono / Flux-utgiveren.

4.3. Forbereder en forespørsel

Først må vi spesifisere en HTTP-metode for en forespørsel ved å påkalle metode (HttpMethod metode) eller kaller snarveimetoder som , post, og slett:

WebClient.UriSpec-forespørsel1 = client3.method (HttpMethod.POST); WebClient.UriSpec request2 = client3.post ();

Det neste trinnet er å oppgi en URL. Vi kan gi den til uri API som en String eller a java.net.URL forekomst:

WebClient.RequestBodySpec uri1 = client3 .metode (HttpMethod.POST) .uri ("/ ressurs"); WebClient.RequestBodySpec uri2 = client3 .post () .uri (URI.create ("/ resource"));

Deretter kan vi angi en forespørsel, innholdstype, lengde, informasjonskapsler eller overskrifter hvis vi trenger det.

For eksempel, hvis vi ønsker å angi en forespørsel, er det to tilgjengelige måter: fylle den med en Kroppsinnføring eller delegere dette arbeidet til en Forlegger:

WebClient.RequestHeadersSpec requestSpec1 = WebClient .create () .method (HttpMethod.POST) .uri ("/ resource") .body (BodyInserters.fromPublisher (Mono.just ("data")), String.class); WebClient.RequestHeadersSpec requestSpec2 = WebClient .create ("// localhost: 8080") .post () .uri (URI.create ("/ resource")) .body (BodyInserters.fromObject ("data"));

De Kroppsinnføring er et grensesnitt som er ansvarlig for å fylle ut en ReaktivHttpOutputMessage kropp med en gitt utgangsmelding og en kontekst som ble brukt under innsettingen. EN Forlegger er en reaktiv komponent som har ansvaret for å gi et potensielt ubegrenset antall sekvenserte elementer.

Den andre måten er kropp metode, som er en snarvei for originalen kropp (BodyInserter innsetter) metode.

Å lindre prosessen med å fylle a Kroppsinnføring, det er en Kroppsinnleggere klasse med en rekke nyttige verktøymetoder:

Kroppsinnføring inserter1 = BodyInserters .fromPublisher (Abonnent :: onComplete, String.class); 

Det er også mulig med en MultiValueMap:

LinkedMultiValueMap map = new LinkedMultiValueMap (); map.add ("nøkkel1", "verdi1"); map.add ("key2", "value2"); BodyInserter inserter2 = BodyInserters.fromMultipartData (kart); 

Eller ved å bruke et enkelt objekt:

BodyInserter inserter3 = BodyInserters.fromObject (nytt objekt ()); 

Etter at vi har satt inn kroppen, kan vi angi overskrifter, informasjonskapsler og akseptable medietyper. Verdier vil bli lagt til de som allerede er angitt når klienten startes.

Det er også ekstra støtte for de mest brukte overskriftene som “Hvis-ingen-samsvar”, “Hvis-modifisert-siden”, “Godta”, og “Accept-Charset”.

Her er et eksempel på hvordan disse verdiene kan brukes:

WebClient.ResponseSpec respons1 = uri1 .body (inserter3). Header (HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE) .accept (MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML) .acceptCharset (Charset (Charset (Charset) (")." "*") .ifModifiedSince (ZonedDateTime.now ()) .hent ();

4.4. Få svar

Den siste fasen er å sende forespørselen og motta svar. Dette kan gjøres med enten Utveksling eller hente metode.

Disse metodene er forskjellige i returtyper; de Utveksling metoden gir en ClientResponse sammen med status og overskrifter, mens hente metoden er den korteste veien for å hente en kropp direkte:

Strengrespons2 = forespørsel1.utveksling () .blokk () .bodyToMono (String.klasse) .blokk (); Stringrespons3 = forespørsel2 .hent () .bodyToMono (String.class) .block ();

Det er viktig å ta hensyn til bodyToMono metode, som vil kaste en WebClientException hvis statuskoden er 4xx (klientfeil) eller 5xx (serverfeil). Vi bruker blokkere metode på Monos for å abonnere og hente faktiske data som ble sendt med svaret.

5. Arbeide med WebTestClient

De WebTestClient er det viktigste inngangspunktet for testing av WebFlux-serverendepunkter. Den har en veldig lignende API til WebClient, og det delegerer mesteparten av arbeidet til et internt WebClient eksempel med hovedvekt på å gi en testkontekst. De StandardWebTestClient klasse er en enkelt grensesnittimplementering.

Klienten for testing kan være bundet til en ekte server eller jobbe med spesifikke kontrollere eller funksjoner.

5.1. Binding til en server

For å fullføre end-to-end integrasjonstester med faktiske forespørsler til en server som kjører, kan vi bruke bindToServer metode:

WebTestClient testClient = WebTestClient .bindToServer () .baseUrl ("// localhost: 8080") .build (); 

5.2. Binding til en ruter

Vi kan teste et bestemt RouterFunction ved å sende den til bindToRouterFunction metode:

RouterFunction-funksjon = RouterFunctions.route (RequestPredicates.GET ("/ resource"), forespørsel -> ServerResponse.ok (). Build ()); WebTestClient .bindToRouterFunction (function) .build (). Get (). Uri ("/ resource") .exchange () .expectStatus (). IsOk () .expectBody (). IsEmpty (); 

5.3. Binding til en nettbehandler

Den samme oppførselen kan oppnås med bindToWebHandler metode, som tar en WebHandler forekomst:

WebHandler handler = exchange -> Mono.empty (); WebTestClient.bindToWebHandler (behandler) .build ();

5.4. Binding til en applikasjonskontekst

En mer interessant situasjon oppstår når vi bruker bindToApplicationContext metode. Det tar en ApplicationContext og analyserer konteksten for controller bønner og @EnableWebFlux konfigurasjoner.

Hvis vi injiserer en forekomst av ApplicationContext, kan en enkel kodebit se slik ut:

@Autowired privat ApplicationContext kontekst; WebTestClient testClient = WebTestClient.bindToApplicationContext (context) .build (); 

5.5. Binding til en kontroller

En kortere tilnærming ville være å gi en rekke kontrollere vi vil teste av bindToController metode. Forutsatt at vi har en Kontroller klasse og vi injiserte den i en nødvendig klasse, kan vi skrive:

@Autowired privat kontroller; WebTestClient testClient = WebTestClient.bindToController (kontroller) .build (); 

5.6. Lager en forespørsel

Etter å ha bygget en WebTestClient objekt, alle følgende operasjoner i kjeden kommer til å ligne på WebClient til Utveksling metode (en måte å få svar på), som gir WebTestClient.ResponseSpec grensesnitt for å jobbe med nyttige metoder som expectStatus, expectBody, og expectHeader:

WebTestClient .bindToServer () .baseUrl ("// localhost: 8080") .build () .post () .uri ("/ resource"). Exchange () .expectStatus (). IsCreated () .expectHeader (). ValueEquals ("Content-Type", "application / json") .expectBody (). IsEmpty (); 

6. Konklusjon

I denne artikkelen undersøkte vi Webklient, en ny forbedret fjærmekanisme for å komme med forespørsler på klientsiden.

Vi så også på fordelene det gir ved å gå gjennom å konfigurere klienten, forberede forespørselen og behandle svaret.

Alle kodebitene som er nevnt i artikkelen, finner du i GitHub-depotet vårt.