Sprievodca okHttp

1. Úvod

V tomto článku si ukážeme základy odosielania rôznych typov požiadaviek HTTP, prijímania a interpretácie odpovedí HTTP, a ako nakonfigurovať klienta pomocou OkHttp.

Prejdeme tiež k pokročilejším prípadom použitia konfigurácie klienta s vlastnými hlavičkami, časovými limitmi, ukladaním do pamäte cache atď.

2. OkHttp Prehľad

OkHttp je efektívny klient HTTP a HTTP / 2 pre aplikácie pre Android a Java.

Dodáva sa s pokročilými funkciami, ako je združovanie pripojení (ak protokol HTTP / 2 nie je k dispozícii), transparentná kompresia GZIP a ukladanie do vyrovnávacej pamäte, aby sa sieť pri opakovaných požiadavkách úplne vyhla.

Je tiež schopný zotaviť sa z bežných problémov s pripojením a v prípade zlyhania pripojenia, ak má služba viac adries IP, môže skúsiť požiadavku na alternatívne adresy.

Na vysokej úrovni je klient navrhnutý na blokovanie synchrónnych aj neblokujúcich asynchrónnych hovorov.

OkHttp podporuje Android 2.3 a novší. Pre Java je minimálna požiadavka 1,7.

Po tomto krátkom prehľade si ukážeme niekoľko príkladov použitia.

3. Maven závislosť

Najprv pridajme knižnicu ako závislosť do pom.xml:

 com.squareup.okhttp3 okhttp 3.4.2 

Najnovšiu závislosť tejto knižnice nájdete na stránke Maven Central.

4. Synchrónne ZÍSKAJTE S OkHttp

Na odoslanie synchrónnej žiadosti GET musíme vytvoriť Žiadosť objekt založený na a URL a urobte Volaj. Po jeho vykonaní dostaneme späť inštanciu Odozva:

@ Test public void whenGetRequest_thenCorrect () hodí IOException {Request request = new Request.Builder () .url (BASE_URL + "/ date") .build (); Volať hovor = client.newCall (požiadavka); Odozva reakcia = call.execute (); assertThat (response.code (), equalTo (200)); }

5. Asynchrónne ZÍSKAJTE S OkHttp

Teraz, aby sme vytvorili asynchrónny GET, musíme zaradiť a Volaj. A Zavolaj späť umožňuje nám prečítať odpoveď, keď je čitateľná. To sa stane, keď sú hlavičky odpovedí pripravené.

Čítanie tela odpovede môže byť stále zablokované. OkHttp v súčasnosti neponúka žiadne asynchrónne API na príjem tela odpovede po častiach:

@Test public void whenAsynchronousGetRequest_thenCorrect () {Request request = new Request.Builder () .url (BASE_URL + "/ date") .build (); Volať hovor = client.newCall (požiadavka); call.enqueue (new Callback () {public void onResponse (Call call, Response response) hodí IOException {// ...} public void onFailure (Call call, IOException e) {fail ();}}); }

6. ZÍSKAJTE S parametrami dotazu

Nakoniec na pridanie parametrov dotazu k našej požiadavke GET môžeme využiť výhody HttpUrl.Builder.

Po vytvorení adresy URL ju môžeme odovzdať našej Žiadosť objekt:

@Test public void whenGetRequestWithQueryParameter_thenCorrect () vyvolá IOException {HttpUrl.Builder urlBuilder = HttpUrl.parse (BASE_URL + "/ ex / bars"). NewBuilder (); urlBuilder.addQueryParameter ("id", "1"); Reťazec url = urlBuilder.build (). ToString (); Request request = nový Request.Builder () .url (url) .build (); Volať hovor = client.newCall (požiadavka); Odozva odpoveď = call.execute (); assertThat (response.code (), equalTo (200)); }

7. POST požiadavka

Pozrime sa na jednoduchú požiadavku POST, kde zostavujeme RequestBody na odoslanie parametrov „Používateľské meno“ a „Heslo“:

@Test public void whenSendPostRequest_thenCorrect () hodí IOException {RequestBody formBody = new FormBody.Builder () .add ("používateľské meno", "test") .add ("heslo", "test") .build (); Vyžiadanie požiadavky = nový Request.Builder () .url (BASE_URL + "/ users") .post (formBody) .build (); Volať hovor = client.newCall (požiadavka); Odozva reakcia = call.execute (); assertThat (response.code (), equalTo (200)); }

Náš článok Stručný sprievodca po zverejňovaní požiadaviek pomocou OkHttp obsahuje ďalšie príklady POST požiadaviek pomocou OkHttp.

8. Nahrávanie súborov

8.1. Nahrajte súbor

V tomto príklade uvidíme, ako nahrať a Súbor. Nahráme „test.ext ” súbor pomocou MultipartBody.Builder:

@Test public void whenUploadFile_thenCorrect () throws IOException {RequestBody requestBody = new MultipartBody.Builder () .setType (MultipartBody.FORM) .addFormDataPart ("file", "file.txt", RequestBody.create (MediaType.parse ("application) octet-stream "), nový Súbor (" src / test / resources / test.txt ")))) .build (); Request request = nový Request.Builder () .url (BASE_URL + "/ users / upload") .post (requestBody) .build (); Volať hovor = client.newCall (požiadavka); Odozva odpoveď = call.execute (); assertThat (response.code (), equalTo (200)); }

8.2. Získajte priebeh nahrávania súborov

Na záver sa pozrime, ako dosiahnuť pokrok v a Súbor nahrať. Predĺžime RequestBody na zviditeľnenie procesu nahrávania.

Najprv je tu metóda nahrávania:

@Test public void whenGetUploadFileProgress_thenCorrect () throws IOException {RequestBody requestBody = new MultipartBody.Builder () .setType (MultipartBody.FORM) .addFormDataPart ("file", "file.txt", RequestBody.create (MediaType.parate) octet-stream "), nový Súbor (" src / test / resources / test.txt ")))) .build (); ProgressRequestWrapper.ProgressListener poslucháč = (bytesWritten, contentLength) -> {float percent = 100f * bytesWritten / contentLength; assertFalse (Float.compare (percento, 100)> 0); }; ProgressRequestWrapper counttingBody = nový ProgressRequestWrapper (requestBody, poslucháč); Vyžiadanie požiadavky = nový Request.Builder () .url (BASE_URL + "/ users / upload") .post (countBody) .build (); Volať hovor = client.newCall (požiadavka); Odozva reakcia = call.execute (); assertThat (response.code (), equalTo (200)); } 

Tu je rozhranie ProgressListener ktorý nám umožňuje sledovať priebeh nahrávania:

verejné rozhranie ProgressListener {void onRequestProgress (long bytesWritten, long contentLength); }

Tu je ProgressRequestWrapper čo je rozšírená verzia RequestBody:

verejná trieda ProgressRequestWrapper rozširuje RequestBody {@Override public void writeTo (umývadlo BufferedSink) hodí IOException {BufferedSink bufferedSink; counttingSink = nový CountingSink (drez); bufferedSink = Okio.buffer (counttingSink); delegate.writeTo (bufferedSink); bufferedSink.flush (); }}

Nakoniec je tu CountingSink čo je rozšírená verzia preposielaniadrez :

chránená trieda CountingSink rozširuje ForwardingSink {private long bytesWritten = 0; public CountingSink (Sink delegate) {super (delegát); } @Override public void write (zdroj vyrovnávacej pamäte, dlhý byteCount) hodí IOException {super.write (zdroj, byteCount); bytesWritten + = byteCount; listener.onRequestProgress (bytesWritten, contentLength ()); }}

Poznač si to:

  • Pri predlžovaní ForwardingSink do „CountingSink“, prepíšeme metódu write (), aby sme spočítali zapísané (prenesené) bajty
  • Pri predlžovaní RequestBody ProgressRequestWrapper „, Prepíšeme metódu writeTo (), aby sme mohli použiť našu „ForwardingSink“

9. Nastavenie vlastnej hlavičky

9.1. Nastavenie hlavičky na požiadanie

Ak chcete nastaviť ľubovoľnú vlastnú hlavičku na a Žiadosť môžeme použiť jednoduchý addHeader hovor:

@ Test public void whenSetHeader_thenCorrect () hodí IOException {Request request = new Request.Builder () .url (SAMPLE_URL) .addHeader ("Content-Type", "application / json") .build (); Volať hovor = client.newCall (požiadavka); Odozva reakcia = call.execute (); response.close (); }

9.2. Nastavenie predvolenej hlavičky

V tomto príklade uvidíme, ako nakonfigurovať predvolenú hlavičku na samotnom klientovi namiesto nastavenia pre každú požiadavku.

Napríklad ak chceme nastaviť typ obsahu „Application / json“ pre každú požiadavku potrebujeme nastaviť zachytávač pre nášho klienta. Tu je metóda:

@Test public void whenSetDefaultHeader_thenCorrect () hodí IOException {OkHttpClient client = new OkHttpClient.Builder () .addInterceptor (new DefaultContentTypeInterceptor ("application / json")) .build (); Request request = nový Request.Builder () .url (SAMPLE_URL) .build (); Volať hovor = client.newCall (požiadavka); Odozva reakcia = call.execute (); response.close (); }

A tu je DefaultContentTypeInterceptor čo je rozšírená verzia Stíhačka:

verejná trieda DefaultContentTypeInterceptor implementuje Interceptor {public intercept intercept (Interceptor.Chain chain) hodí IOException {Request originalRequest = chain.request (); Vyžiadajte requestWithUserAgent = originalRequest .newBuilder () .header ("Content-Type", contentType) .build (); návrat chain.proceed (requestWithUserAgent); }}

Všimnite si, že zachytávač pridá hlavičku k pôvodnej žiadosti.

10. Nesledujte presmerovania

V tomto príklade uvidíme, ako nakonfigurovať OkHttpClient prestať sledovať presmerovania.

Predvolene, ak je na požiadavku GET odpovedané pomocou HTTP 301 bol presunutý natrvalo presmerovanie sa vykoná automaticky. V niektorých prípadoch to môže byť úplne v poriadku, ale určite existujú prípady, keď to nie je žiaduce.

Aby sme dosiahli toto správanie, musíme pri budovaní nášho klienta nastaviť followRedirects do nepravdivé.

Upozorňujeme, že odpoveď vráti znak HTTP 301 stavový kód:

@ Test public void whenSetFollowRedirects_thenNotRedirected () vyvolá IOException {OkHttpClient client = new OkHttpClient (). NewBuilder () .followRedirects (false) .build (); Žiadosť request = new Request.Builder () .url ("// t.co/I5YYd9tddw") .build (); Volať hovor = client.newCall (požiadavka); Odozva reakcia = call.execute (); assertThat (response.code (), equalTo (301)); } 

Ak presmerovanie zapneme pomocou a pravda parameter (alebo ho úplne odstráňte), klient bude nasledovať presmerovanie a test zlyhá, pretože návratovým kódom bude HTTP 200.

11. Časové limity

Použite časové limity na zlyhanie hovoru, keď je jeho partner nedostupný. Poruchy siete môžu byť spôsobené problémami s pripojením klienta, problémami s dostupnosťou servera alebo čímkoľvek iným. OkHttp podporuje časové limity pripojenia, čítania a zápisu.

V tomto príklade sme postavili nášho klienta pomocou a readTimeout 1 s, zatiaľ čo URL je doručené s 2 s oneskorením:

@Test public void whenSetRequestTimeout_thenFail () hodí IOException {OkHttpClient client = new OkHttpClient.Builder () .readTimeout (1, TimeUnit.SECONDS) .build (); Request request = nový Request.Builder () .url (BASE_URL + "/ delay / 2") .build (); Volať hovor = client.newCall (požiadavka); Odozva reakcia = call.execute (); assertThat (response.code (), equalTo (200)); }

Upozorňujeme, že test zlyhá, pretože časový limit klienta je nižší ako čas odozvy zdroja.

12. Zrušenie hovoru

Použite Call.cancel () okamžité zastavenie prebiehajúceho hovoru. Ak vlákno práve píše požiadavku alebo číta odpoveď, an Výnimka IO bude vyhodený.

Toto použite na zachovanie siete v prípade, že hovor už nie je potrebný. napríklad keď váš používateľ opustí aplikáciu:

@Test (očakáva sa = IOException.class) public void whenCancelRequest_thenCorrect () vyvolá IOException {ScheduledExecutorService Exekútor = Executors.newScheduledThreadPool (1); Request request = nový Request.Builder () .url (BASE_URL + "/ delay / 2") .build (); int sekundy = 1; long startNanos = System.nanoTime (); Volať hovor = client.newCall (požiadavka); executor.schedule (() -> {logger.debug ("Zrušenie hovoru:" + (System.nanoTime () - startNanos) / 1e9f); call.cancel (); logger.debug ("Zrušené volanie:" + (systém) .nanoTime () - startNanos) / 1e9f);}, sekundy, TimeUnit.SECONDS); logger.debug ("Vykonávajúci hovor:" + (System.nanoTime () - startNanos) / 1e9f); Odozva odpoveď = call.execute (); logger.debug (Očakávalo sa, že hovor zlyhal, ale bol dokončený: "+ (System.nanoTime () - startNanos) / 1e9f, odpoveď);}

13. Uloženie odpovede do pamäte cache

Ak chcete vytvoriť Cache, budeme potrebovať adresár cache, do ktorého môžeme čítať a zapisovať, a obmedzenie veľkosti cache.

Klient ho použije na uloženie odpovede do pamäte cache:

@ Test public void whenSetResponseCache_thenCorrect () vyvolá IOException {int cacheSize = 10 * 1024 * 1024; File cacheDirectory = nový súbor ("src / test / resources / cache"); Cache cache = nová Cache (cacheDirectory, cacheSize); OkHttpClient client = nový OkHttpClient.Builder () .cache (cache) .build (); Request request = new Request.Builder () .url ("// publicobject.com/helloworld.txt") .build (); Odozva response1 = client.newCall (request) .execute (); logResponse (response1); Odozva response2 = client.newCall (request) .execute (); logResponse (response2); }

Po spustení testu nebude odpoveď z prvého hovoru do pamäte cache. Výzva metódy cacheResponse vráti sa nulový, zatiaľ čo volanie metódy networkResponse vráti odpoveď zo siete.

Priečinok medzipamäte bude tiež naplnený súbormi medzipamäte.

Vykonanie druhého hovoru bude mať opačný efekt, pretože odpoveď bude už uložená v pamäti. To znamená, že hovor na networkResponse vráti sa nulový počas hovoru na cacheResponse vráti odpoveď z cache.

Ak chcete zabrániť použitiu medzipamäte odpoveďou, použite CacheControl.FORCE_NETWORK. Ak chcete zabrániť v používaní siete, použite CacheControl.FORCE_CACHE.

Varovanie: ak používate FORCE_CACHE a odpoveď vyžaduje sieť, OkHttp vráti odpoveď 504 Neuspokojivá žiadosť.

14. Záver

V tomto článku sme videli niekoľko príkladov, ako používať OkHttp ako klienta HTTP a HTTP / 2.

Vzorový kód nájdete ako vždy v projekte GitHub.


$config[zx-auto] not found$config[zx-overlay] not found