Útmutató az OkHttp webhelyhez

1. Bemutatkozás

Ebben a cikkben bemutatjuk a különféle típusú HTTP kérések küldésének, a HTTP válaszok fogadásának és értelmezésének alapjait, és hogyan konfigurálhat egy klienst az OkHttp segítségével.

Ezenkívül részletesebb felhasználási esetekkel is foglalkozunk, amikor az ügyfél egyéni fejlécekkel, időkorlátokkal, válasz-gyorsítótárral stb. Konfigurálható.

2. OkHttp áttekintés

Az OkHttp egy hatékony HTTP és HTTP / 2 kliens Android és Java alkalmazásokhoz.

Olyan fejlett funkciókkal rendelkezik, mint a kapcsolatkészlet (ha a HTTP / 2 nem áll rendelkezésre), az átlátszó GZIP-tömörítés és a válasz-gyorsítótár, hogy elkerülje a hálózatot teljesen az ismételt kérések esetén.

Ugyancsak képes helyreállni a gyakori csatlakozási problémákból, és a kapcsolat meghibásodása esetén, ha egy szolgáltatásnak több IP-címe van, akkor újból megkísérelheti az alternatív címek kérését.

Magas szinten az ügyfelet mind a szinkron, mind a nem blokkoló aszinkron hívások blokkolására tervezték.

Az OkHttp támogatja az Android 2.3 és újabb verziókat. A Java esetében a minimális követelmény 1,7.

E rövid áttekintés után nézzünk meg néhány használati példát.

3. Maven-függőség

Először adjuk hozzá a könyvtárat függőségként a könyvtárba pom.xml:

 com.squareup.okhttp3 okhttp 3.4.2 

A könyvtár legújabb függőségének megtekintéséhez keresse fel a Maven Central oldalt.

4. Szinkron GET az OkHttp-vel

Szinkron GET kérés küldéséhez ki kell építenünk egy Kérés objektum alapján a URL és készítsen egy Hívás. A végrehajtása után visszakapjuk a Válasz:

@Test public void, amikor a GetRequest_thenCorrect () az IOException-t dobja {Request request = new Request.Builder () .url (BASE_URL + "/ date") .build (); Call call = client.newCall (kérés); Válaszválasz = call.execute (); assertThat (válasz.kód (), egyenlőTo (200)); }

5. Aszinkron GET az OkHttp-vel

Ahhoz, hogy aszinkron GET-t készítsünk, be kell mutatnunk a Hívás. A Visszahív lehetővé teszi számunkra a válasz elolvasását, amikor az olvasható. Ez a válaszfejléc készenléte után történik.

A válasz törzsének olvasása továbbra is blokkolhatja. Az OkHttp jelenleg nem kínál aszinkron API-kat a válasz törzsének részenként történő fogadásához:

@Test public void whenAsynchronousGetRequest_thenCorrect () {Request request = new Request.Builder () .url (BASE_URL + "/ date") .build (); Call call = client.newCall (kérés); call.enqueue (new Callback () {public void onResponse (Call call, Response response) dobja az IOException-t {// ...} public void onFailure (Call call, IOException e) {fail ();}}); }

6. GET lekérdezési paraméterekkel

Végül a lekérdezési paraméterek hozzáadásához a GET kéréshez kihasználhatjuk a HttpUrl.Builder.

Az URL felépítése után átadhatjuk nekünk Kérés tárgy:

@Test public void, amikor aGetRequestWithQueryParameter_thenCorrect () az IOException-t dobja {HttpUrl.Builder urlBuilder = HttpUrl.parse (BASE_URL + "/ ex / bars"). NewBuilder (); urlBuilder.addQueryParameter ("id", "1"); String url = urlBuilder.build (). ToString (); Request request = új Request.Builder () .url (url) .build (); Call call = client.newCall (kérés); Válaszválasz = call.execute (); assertThat (válasz.kód (), egyenlőTo (200)); }

7. POST kérés

Nézzünk meg egy egyszerű POST kérést, ahol felépítjük a RequestBody a paraméterek elküldéséhez "felhasználónév" és "Jelszó":

@Test public void, amikor a SENDPostRequest_thenCorrect () dobja az IOException {RequestBody formBody = új FormBody.Builder () .add ("felhasználónév", "teszt") .add ("jelszó", "teszt") .build (); Request request = új Request.Builder () .url (BASE_URL + "/ users") .post (formBody) .build (); Call call = client.newCall (kérés); Válaszválasz = call.execute (); assertThat (válasz.kód (), egyenlőTo (200)); }

Az OkHttp-vel kapcsolatos kérelmek gyors útmutatója című cikkünk további példákat tartalmaz az OkHttp-vel kapcsolatos POST-kérelmekre.

8. Fájl feltöltés

8.1. Feltölteni egy fájlt

Ebben a példában megnézzük, hogyan lehet feltölteni a File. Feltöltjük atest.ext ” fájl segítségével MultipartBody.Builder:

@Test public void whenUploadFile_thenCorrect () IOException {RequestBody requestBody = new MultipartBody.Builder () .setType (MultipartBody.FORM) .addFormDataPart ("file", "file.txt", RequestBody.create (MediaType.parse (MediaType.parse) octet-stream "), új File (" src / test / resources / test.txt "))) .build (); Request request = új Request.Builder () .url (BASE_URL + "/ users / upload") .post (requestBody) .build (); Call call = client.newCall (kérés); Válaszválasz = call.execute (); assertThat (válasz.kód (), egyenlőTo (200)); }

8.2. Fájlfeltöltés előrehaladása

Végül nézzük meg, hogyan lehet elérni a File feltölteni. Meghosszabbítjuk RequestBody hogy láthassák a feltöltési folyamatot.

Először a következő feltöltési módszer:

@Test public void whenGetUploadFileProgress_thenCorrect () dobja az IOException {RequestBody requestBody = new MultipartBody.Builder () .setType (MultipartBody.FORM) .addFormDataPart ("fájl", "file.txt", RequestBody.create (MediaTy) octet-stream "), új File (" src / test / resources / test.txt "))) .build (); ProgressRequestWrapper.ProgressListener hallgató = (bytesWritten, contentLength) -> {lebegési százalék = 100f * bytesWritten / contentLength; assertFalse (Float.compare (százalékos, 100)> 0); }; ProgressRequestWrapper countingBody = új ProgressRequestWrapper (requestBody, hallgató); Request request = új Request.Builder () .url (BASE_URL + "/ users / upload") .post (countingBody) .build (); Call call = client.newCall (kérés); Válaszválasz = call.execute (); assertThat (válasz.kód (), egyenlőTo (200)); } 

Itt van a felület ProgressListener amely lehetővé teszi számunkra a feltöltés előrehaladásának megfigyelését:

nyilvános felület ProgressListener {void onRequestProgress (hosszú bytesWritten, hosszú contentLength); }

Itt van ProgressRequestWrapper amely a kiterjesztett változata RequestBody:

public class ProgressRequestWrapper kiterjeszti a RequestBody {@Override public void writeTo (BufferedSink mosogató) dobja az IOException {BufferedSink bufferedSink; countingSink = new CountingSink (mosogató); bufferedSink = Okio.buffer (countingSink); delegate.writeTo (bufferedSink); bufferedSink.flush (); }}

Végül itt van a CountingSink amely a továbbítás kiterjesztett változataMosogató :

védett osztály a CountingSink kiterjeszti a ForwardingSink {private long bytesWritten = 0; public CountingSink (Sink delegate) {szuper (delegált); } @Orride public void write (puffer forrás, hosszú byteCount) dobja az IOException {super.write (forrás, byteCount); bytesWritten + = byteCount; listener.onRequestProgress (bytesWritten, contentLength ()); }}

Vegye figyelembe, hogy:

  • Hosszabbításkor ForwardingSink nak nek „CountingSink”, felülírjuk az write () metódust az írott (átvitt) bájtok számlálásához
  • Hosszabbításkor RequestBody nak nek "ProgressRequestWrapper “, Felülírjuk a writeTo () metódust a mi használatához “ForwardingSink”

9. Egyéni fejléc beállítása

9.1. Fejléc beállítása kérésre

Bármelyik egyéni fejléc beállítása a Kérés használhatunk egy egyszerű addHeader hívás:

@Test public void whenSetHeader_thenCorrect () IOException dobja {Request request = new Request.Builder () .url (SAMPLE_URL) .addHeader ("Content-Type", "application / json") .build (); Call call = client.newCall (kérés); Válaszválasz = call.execute (); válasz.zár (); }

9.2. Alapértelmezett fejléc beállítása

Ebben a példában azt fogjuk látni, hogyan állítsunk be egy alapértelmezett fejlécet magában az ügyfélben, ahelyett, hogy minden egyes kérésre beállítanánk.

Például, ha egy tartalomtípust akarunk beállítani „Alkalmazás / json” minden kéréshez be kell állítanunk egy elfogót ügyfelünk számára. Itt van a módszer:

@Test public void whenSetDefaultHeader_thenCorrect () dobja az IOException {OkHttpClient kliens = új OkHttpClient.Builder () .addInterceptor (új DefaultContentTypeInterceptor ("alkalmazás / json")) .build (); Request request = új Request.Builder () .url (SAMPLE_URL) .build (); Call call = client.newCall (kérés); Válaszválasz = call.execute (); válasz.zár (); }

És itt van a DefaultContentTypeInterceptor amely a kiterjesztett változata Elfogó:

public class DefaultContentTypeInterceptor végrehajtja az Interceptor {public Response intercept (Interceptor.Chain chain) dobja az IOException-t {Request originalRequest = chain.request (); Request requestWithUserAgent = originalRequest .newBuilder () .header ("Content-Type", contentType) .build (); return chain.proceed (requestWithUserAgent); }}

Vegye figyelembe, hogy az elfogó hozzáadja a fejlécet az eredeti kéréshez.

10. Ne kövesse az átirányításokat

Ebben a példában megnézzük, hogyan kell konfigurálni a OkHttpClient hogy abbahagyja az átirányítások követését.

Alapértelmezés szerint, ha egy GET kérésre egy HTTP 301 véglegesen áthelyezve az átirányítás automatikusan követésre kerül. Bizonyos használati esetekben ez teljesen rendben lehet, de természetesen vannak olyan esetek, amikor ez nem kívánatos.

Ennek a viselkedésnek az eléréséhez, amikor felépítjük ügyfelünket, beállítanunk kell followRedirects nak nek hamis.

Vegye figyelembe, hogy a válasz egy HTTP 301 állapotkód:

@Test public void, amikor aSetFollowRedirects_thenNotRedirected () dobja az IOException {OkHttpClient kliens = új OkHttpClient (). NewBuilder () .followRedirects (hamis) .build (); Request request = új Request.Builder () .url ("// t.co/I5YYd9tddw") .build (); Call call = client.newCall (kérés); Válaszválasz = call.execute (); assertThat (válasz.kód (), egyenlőTo (301)); } 

Ha bekapcsoljuk az átirányítást a-val igaz paraméter (vagy távolítsa el teljesen), az ügyfél követi az átirányítást, és a teszt sikertelen lesz, mivel a visszatérési kód HTTP 200 lesz.

11. Időkorlátok

Az időkorlátok használatával sikertelen a hívás, ha a társa elérhetetlen. A hálózati hibák oka lehet az ügyfél csatlakozási problémája, a kiszolgáló elérhetőségének problémája vagy bármi más. Az OkHttp támogatja a kapcsolódási, olvasási és írási időkorlátokat.

Ebben a példában építettük meg ügyfelünket a readTimeout 1 másodpercig, míg az URL 2 másodperces késéssel jelenik meg:

@Test public void, amikor aSetRequestTimeout_thenFail () dobja az IOException {OkHttpClient kliens = új OkHttpClient.Builder () .readTimeout (1, TimeUnit.SECONDS) .build (); Request request = új Request.Builder () .url (BASE_URL + "/ delay / 2") .build (); Call call = client.newCall (kérés); Válaszválasz = call.execute (); assertThat (válasz.kód (), egyenlőTo (200)); }

Vegye figyelembe, hogy a teszt sikertelen lesz, mivel az ügyfél időtúllépése alacsonyabb, mint az erőforrás válaszideje.

12. Hívás lemondása

Használat Call.cancel () hogy azonnal leállítsa a folyamatban lévő hívást. Ha egy szál éppen kérést ír vagy választ olvas, akkor egy IOException dobni fogják.

Használja ezt a hálózat megóvására, ha már nincs szükség hívásra; például amikor a felhasználó eltávolodik egy alkalmazástól:

@Test (várható = IOException.class) public void, amikor aCancelRequest_thenCorrect () dobja az IOException-t {ScheduledExecutorService végrehajtó = Executors.newScheduledThreadPool (1); Request request = új Request.Builder () .url (BASE_URL + "/ delay / 2") .build (); int másodperc = 1; long startNanos = System.nanoTime (); Call call = client.newCall (kérés); végrehajtó.schedule (() -> {logger.debug ("Hívás törlése:" + (System.nanoTime () - startNanos) / 1e9f); call.cancel (); logger.debug ("Törölt hívás:" + (Rendszer .nanoTime () - startNanos) / 1e9f);}, másodperc, TimeUnit.SECONDS); logger.debug ("Hívás végrehajtása:" + (System.nanoTime () - startNanos) / 1e9f); Válaszválasz = call.execute (); logger.debug (A hívás várhatóan meghiúsult, de befejeződött: "+ (System.nanoTime () - startNanos) / 1e9f, válasz);}

13. Válasz gyorsítótárazás

A Gyorsítótár, szükségünk lesz egy gyorsítótár-könyvtárra, amelybe olvashatunk és írhatunk, valamint korlátozni kell a gyorsítótár méretét.

Az ügyfél a válasz gyorsítótárazására fogja használni:

@Test public void whenSetResponseCache_thenCorrect () IOException dobja {int cacheSize = 10 * 1024 * 1024; File cacheDirectory = új fájl ("src / test / resources / cache"); Cache cache = új gyorsítótár (cacheDirectory, cacheSize); OkHttpClient kliens = új OkHttpClient.Builder () .cache (cache) .build (); Request request = új Request.Builder () .url ("// publicobject.com/helloworld.txt") .build (); Válaszválasz1 = client.newCall (request) .execute (); logResponse (válasz1); Válaszválasz2 = client.newCall (request) .execute (); logResponse (válasz2); }

A teszt elindítása után az első hívás válasza nem lesz gyorsítótárban. Hívás a módszerre cacheResponse vissza fog térni nulla, míg a módszer hívása networkResponse visszaadja a választ a hálózatról.

Ezenkívül a gyorsítótár mappája meg lesz töltve a gyorsítótár fájlokkal.

A második hívás végrehajtása ellentétes hatást vált ki, mivel a válasz már tárolásra került. Ez azt jelenti, hogy felhívás networkResponse vissza fog térni nulla miközben felhívás cacheResponse visszaadja a választ a gyorsítótárból.

A gyorsítótár használatának megakadályozásához használja a CacheControl.FORCE_NETWORK. A hálózat használatának megakadályozásához használja a CacheControl.FORCE_CACHE.

Figyelmeztetni kell: ha használja FORCE_CACHE és a válaszhoz a hálózatra van szükség, OkHttp 504 Nem kielégítő kérelem választ ad vissza.

14. Következtetés

Ebben a cikkben számos példát láthattunk arra vonatkozóan, hogyan lehet az OkHttp-t HTTP és HTTP / 2 kliensként használni.

Mint mindig, a példakód megtalálható a GitHub projektben.