2016/03/05

OkHttp Interceptor

本稿ではOkHttpのApplication InterceptorとNetwork Interceptorの役割について書きました.
内容はOkHttp公式wiki - Interceptorsと被っていますが, メモとして残します.

Interceptor

OkHttpでは処理に割り込めるポイントが2つあり, 必要に応じて使い分けます.

OkHttp Interceptor

アプリケーションとOkHttpとのコミュニケーションに割り込むInterceptorをApplicationInterceptor, OkHttpとネットワークとのコミュニケーションに割り込むInterceptorをNetworkInterceptorと呼びます.

これらはOkHttpClient.Builderを経由して設定できます.

OkHttpClient client = new OkHttpClient.Builder()
    .addInterceptor(new LoggingInterceptor())
    .addNetworkInterceptor(new LoggingInterceptor())
    .build();

挙動の違い

OkHttpはアプリケーションが楽できるように様々な処理を代行します.

Redirect, Retryの処理はアプリとのコミュニケーションなしに, OkHttpに閉じて行われます.
そういったアプリとのコミュニケーションが発生しないケースではApplicationInterceptorが使えません.

Redirect, Retryの処理はネットワークとのコミュニケーションになります. ここへ割り込むにはNetworkInterceptorが使えます.
ただし, Cacheレスポンスが働く場合はネットワークとのコミュニケーションが発生しません.
そういったネットワークとのコミュニケーションが発生しないケースではNetworkInterceptorが使えません.

各Interceptorのポイントを下記に纏めます.

ApplicationInterceptor

  • RedirectやRetryといった中間応答には反応できない
  • Cacheレスポンスにも反応する
  • アプリケーションが発行するオリジナルリクエストが監視対象

NetworkInterceptor

  • RedirectやRetryといった中間応答にも反応できる
  • Cacheレスポンスには反応できない
  • ネットワークへ発行されるリクエストが監視対象

監視対象リクエストについて. OkHttpはアプリからのリクエストを加工して通信します.
この時, アプリからリクエストされたオリジナルの内容はApplicationInterceptorが補足します.
その後, OkHttpが加工したリクエストはNetworkInterceptorが補足します.

client.newCall(new Request.Builder()
        .url(url)
        .build())
        .execute();

上記の単純なGETリクエストを投げるコードで, ApplicationInterceptor, NetworkInterceptorそれぞれにHttpLoggingInterceptorを設定した場合のログ出力を確認します.

// ApplicationInterceptorによる出力
--> GET http://127.0.0.1:54817/ http/1.1
--> END GET

// NetworkInterceptorによる出力
--> GET http://127.0.0.1:54817/ http/1.1
Host: 127.0.0.1:54817
Connection: Keep-Alive
Accept-Encoding: gzip
User-Agent: okhttp/3.2.0
--> END GET

リクエストを加工する工程がみて取れました.

他にも, OkHttpにCookie管理を任せてCookieヘッダをログで確認したい場合はNetworkInterceptorを使います.

CookieManager cookieManager 
    = new CookieManager(null, ACCEPT_ORIGINAL_SERVER);
CookieHandler.setDefault(cookieManager);

server.enqueue(new MockResponse()
    .addHeader("Set-Cookie: a=hoge;")
    .addHeader("Set-Cookie: b=foo;"));
server.enqueue(new MockResponse());

client = client.newBuilder()
    .cookieJar(new JavaNetCookieJar(cookieManager))
    .build();

requestGet(urlWithIpAddress(server, "/"));
requestGet(urlWithIpAddress(server, "/"));
--> GET http://127.0.0.1:56899/ http/1.1
Host: 127.0.0.1:56899
Connection: Keep-Alive
Accept-Encoding: gzip
Cookie: a=hoge; b=foo
User-Agent: okhttp/3.2.0
--> END GET

以上です.