Proljeće 5 WebClient

1. Pregled

U ovom uputstvu ispitat ćemo WebClient, koji je reaktivni web klijent predstavljen u proljeće 5.

Također ćemo pogledati WebTestClient, a WebClient dizajniran za upotrebu u testovima.

2. Što je WebClient?

Jednostavno rečeno, WebClient je sučelje koje predstavlja glavnu ulaznu točku za izvršavanje web zahtjeva.

Izrađen je kao dio Spring Web Reactive modula i zamijenit će klasični RestTemplate u tim scenarijima. Uz to, novi je klijent reaktivno, neblokirajuće rješenje koje radi preko protokola HTTP / 1.1.

Konačno, sučelje ima jednu implementaciju, DefaultWebClient klase, s kojom ćemo raditi.

3. Ovisnosti

Budući da koristimo aplikaciju Spring Boot, potreban nam je spring-boot-starter-webflux ovisnosti, kao i projekt Reaktor.

3.1. Zgrada s Mavenom

Dodajmo sljedeće ovisnosti na pom.xml datoteka:

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

3.2. Zgrada sa Gradleom

S Gradleom moramo dodati sljedeće unose u graditi.gradle datoteka:

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

4. Suradnja s WebClient

Da bismo ispravno surađivali s klijentom, moramo znati kako:

  • stvoriti instancu
  • podnijeti zahtjev
  • riješiti odgovor

4.1. Stvaranje a WebClient Primjer

Tri su opcije na izbor. Prvi je stvaranje a WebClient objekt sa zadanim postavkama:

WebClient client1 = WebClient.create (); 

Druga je mogućnost pokretanje a WebClient instanca s danim osnovnim URI-jem:

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

Treća opcija (i ona najnaprednija) je izgradnja klijenta pomoću ZadaniWebClientBuilder klasa, koja omogućuje potpuno prilagođavanje:

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

4.2. Stvaranje a WebClient Instanca s vremenskim ograničenjima

Često su zadana HTTP vremenska ograničenja od 30 sekundi prespora za naše potrebe, pa da vidimo kako ih konfigurirati za naše WebClient primjer.

Osnovna klasa koju koristimo je TcpClient.

Tamo možemo podesite vremensko ograničenje veze putem ChannelOption.CONNECT_TIMEOUT_MILLIS vrijednost. Možemo i mi postavite vremenska ograničenja za čitanje i pisanje pomoću a ReadTimeoutHandler i a WriteTimeoutHandler, odnosno:

TcpClient tcpClient = TcpClient .create () .option (ChannelOption.CONNECT_TIMEOUT_MILLIS, 5000) .doOnConnected (connection -> {connection.addHandlerLast (new ReadTimeoutHandler (5000, TimeUnit.MILLISECONDHand). MILISEKONDI));}); Klijent WebClient = WebClient.builder () .clientConnector (novi ReactorClientHttpConnector (HttpClient.from (tcpClient))) .build ();

Imajte na umu da dok možemo zvati pauza na zahtjev našeg klijenta, ovo je vremensko ograničenje signala, a ne HTTP veza ili vremensko ograničenje čitanja / pisanja; to je timeout za izdavača Mono / Flux.

4.3. Priprema zahtjeva

Prvo moramo odrediti HTTP metodu zahtjeva pozivanjem metoda (metoda HttpMethod) ili pozivanje njegovih metoda prečaca kao što su dobiti, post, i izbrisati:

WebClient.UriSpec request1 = client3.method (HttpMethod.POST); WebClient.UriSpec request2 = client3.post ();

Sljedeći je korak pružanje URL-a. Možemo ga proslijediti uri API kao Niz ili a java.net.URL primjer:

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

Tada možemo postaviti tijelo zahtjeva, vrstu sadržaja, duljinu, kolačiće ili zaglavlja ako je potrebno.

Na primjer, ako želimo postaviti tijelo zahtjeva, dva su dostupna načina: ispunjavanje s BodyInserter ili delegiranje ovog djela na Izdavač:

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"));

The BodyInserter je sučelje odgovorno za popunjavanje a ReactiveHttpOutputMessage tijelo s danom izlaznom porukom i kontekstom koji se koristi tijekom umetanja. A Izdavač je reaktivna komponenta koja je zadužena za pružanje potencijalno neograničenog broja sekvenciranih elemenata.

Drugi način je tijelo metoda, što je prečac za izvornik tijelo (umetak za BodyInserter) metoda.

Da bi se ublažio postupak punjenja a BodyInserter, tamo je BodyInserters razred s nizom korisnih korisnih metoda:

BodyInserter inserter1 = BodyInserters .fromPublisher (Pretplatnik :: onComplete, String.class); 

Moguće je i s MultiValueMap:

Mapa LinkedMultiValueMap = nova LinkedMultiValueMap (); map.add ("key1", "value1"); map.add ("key2", "value2"); BodyInserter inserter2 = BodyInserters.fromMultipartData (karta); 

Ili pomoću jednog objekta:

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

Nakon što postavimo tijelo, možemo postaviti zaglavlja, kolačiće i prihvatljive vrste medija. Vrijednosti će se dodati onima koje su već postavljene prilikom instanciranja klijenta.

Također, postoji dodatna podrška za najčešće korištena zaglavlja poput „Ako se ne podudara“, „Ako se promijenilo-od“, „Prihvaćam“, i "Prihvati-Charset".

Evo primjera kako se ove vrijednosti mogu koristiti:

WebClient.ResponseSpec response1 = uri1 .body (inserter3) .header (HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE) .accept (MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML) .setCharsetFarmen (CharsetCharset) " "*") .ifModifiedSince (ZonedDateTime.now ()) .retrieve ();

4.4. Dobivanje odgovora

Posljednja faza je slanje zahtjeva i primanje odgovora. To se može učiniti s bilo kojim razmjena ili dohvatiti metoda.

Te se metode razlikuju po vrstama povrata; the razmjena metoda pruža a ClientResponse zajedno sa svojim statusom i zaglavljima, dok dohvatiti metoda je najkraći put do izravnog donošenja tijela:

String response2 = request1.exchange () .block () .bodyToMono (String.class) .block (); String response3 = request2 .retrieve () .bodyToMono (String.class) .block ();

Važno je obratiti pažnju na bodyToMono metoda, koja će baciti a WebClientException ako je statusni kod 4xx (pogreška klijenta) ili 5xx (pogreška servera). Koristimo blok metoda na Monos za pretplatu i preuzimanje stvarnih podataka poslanih s odgovorom.

5. Rad s WebTestClient

The WebTestClient glavna je ulazna točka za testiranje krajnjih točaka poslužitelja WebFlux. Ima vrlo sličan API kao WebClient, a većinu posla delegira na internu WebClient primjerice fokusirajući se uglavnom na pružanje testnog konteksta. The DefaultWebTestClient klasa je implementacija jednog sučelja.

Klijent za testiranje može biti vezan za pravi poslužitelj ili raditi sa određenim kontrolerima ili funkcijama.

5.1. Vezivanje na poslužitelj

Da bismo dovršili sveobuhvatne testove integracije sa stvarnim zahtjevima za pokrenut poslužitelj, možemo koristiti bindToServer metoda:

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

5.2. Vezivanje na usmjerivač

Možemo testirati određeno Funkcija usmjerivača prosljeđivanjem na bindToRouterFunction metoda:

Funkcija RouterFunction = RouterFunctions.route (RequestPredicates.GET ("/ resource"), zahtjev -> ServerResponse.ok (). Build ()); WebTestClient .bindToRouterFunction (funkcija) .build (). Get (). Uri ("/ resource") .exchange () .expectStatus (). IsOk () .expectBody (). IsEmpty (); 

5.3. Vezivanje na web rukovatelj

Isto se ponašanje može postići i s bindToWebHandler metoda koja traje a WebHandler primjer:

Rukovatelj WebHandlerom = razmjena -> Mono.empty (); WebTestClient.bindToWebHandler (rukovatelj) .build ();

5.4. Vezanje za kontekst aplikacije

Zanimljivija se situacija događa kada koristimo bindToApplicationContext metoda. Potrebno je ApplicationContext i analizira kontekst za grah kontrolera i @EnableWebFlux konfiguracije.

Ako ubrizgamo instancu ApplicationContext, jednostavni isječak koda može izgledati ovako:

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

5.5. Vezivanje za kontroler

Kraći pristup bio bi pružanje niza kontrolera koje želimo testirati putem bindToController metoda. Pod pretpostavkom da imamo Kontroler klase i ubrizgali smo ga u potreban razred, možemo napisati:

@Autowired privatni kontroler kontrolera; WebTestClient testClient = WebTestClient.bindToController (kontroler) .build (); 

5.6. Podnošenje zahtjeva

Nakon izgradnje a WebTestClient objekt, sve sljedeće operacije u lancu bit će slične WebClient do razmjena metoda (jedan od načina da se dobije odgovor), koja pruža WebTestClient.ResponseSpec sučelje za rad s korisnim metodama poput očekujteStatus, očekivatiBody, i očekivatiHeader:

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

6. Zaključak

U ovom smo članku istražili WebClient, novi poboljšani Spring mehanizam za izradu zahtjeva na strani klijenta.

Također smo pogledali prednosti koje pruža prolazeći kroz konfiguriranje klijenta, pripremu zahtjeva i obradu odgovora.

Svi isječci koda spomenuti u članku mogu se naći u našem GitHub spremištu.