OkHttp 使用小记——缓存和验证

1,003 阅读2分钟

通过入门进阶,完全可以使用OkHttp进行绝大部分工作了,这里再讲两个不太会用到的部分——缓存和验证。

缓存

如果要使用缓存,需要建立一个缓存文件夹,并设置缓存的大小。请注意:

  1. 这个缓存文件夹不能被外部程序访问。
  2. 整个程序应该只使用一个缓存,也就是共享一个OkHttpClient实例。
    3.通过设置HTTP头来为每个请求配置缓存的使用情况,比如Cache-Control: max-age=9600指定缓存的生存期,Cache-Control:no-cache指定不使用缓存。

示例代码:

private final OkHttpClient client;

public CacheResponse(File cacheDirectory) throws Exception {
int cacheSize = 10 * 1024 * 1024; // 10 MiB
Cache cache = new Cache(cacheDirectory, cacheSize);

client = new OkHttpClient.Builder()
    .cache(cache)
    .build();
}

public void run() throws Exception {
Request request = new Request.Builder()
    .url("http://publicobject.com/helloworld.txt")
    .build();

Response response1 = client.newCall(request).execute();
if (!response1.isSuccessful()) throw new IOException("Unexpected code " + response1);

String response1Body = response1.body().string();
System.out.println("Response 1 response:          " + response1);
System.out.println("Response 1 cache response:    " + response1.cacheResponse());
System.out.println("Response 1 network response:  " + response1.networkResponse());

Response response2 = client.newCall(request).execute();
if (!response2.isSuccessful()) throw new IOException("Unexpected code " + response2);

String response2Body = response2.body().string();
System.out.println("Response 2 response:          " + response2);
System.out.println("Response 2 cache response:    " + response2.cacheResponse());
System.out.println("Response 2 network response:  " + response2.networkResponse());

System.out.println("Response 2 equals Response 1? " + response1Body.equals(response2Body));
}

验证

OkHttp会自动重试未验证的请求。当响应是401 Not Authorized时,会要求Authenticator提供证书。Authenticator的实现中需要建立一个包含证书的新请求。如果没有证书可用,返回null来跳过。

示例代码:

  private final OkHttpClient client;

  public Authenticate() {
    client = new OkHttpClient.Builder()
        .authenticator(new Authenticator() {
          @Override public Request authenticate(Route route, Response response) throws IOException {
            System.out.println("Authenticating for response: " + response);
            System.out.println("Challenges: " + response.challenges());
            String credential = Credentials.basic("jesse", "password1");
            return response.request().newBuilder()
                .header("Authorization", credential)
                .build();
          }
        })
        .build();
  }

  public void run() throws Exception {
    Request request = new Request.Builder()
        .url("http://publicobject.com/secrets/hellosecret.txt")
        .build();

    Response response = client.newCall(request).execute();
    if (!response.isSuccessful()) throw new IOException("Unexpected code " + response);

    System.out.println(response.body().string());
  }

通过返回null,可以避免反复进行多次验证:

  if (credential.equals(response.request().header("Authorization"))) {
    return null; // If we already failed with these credentials, don't retry.
   }

或者在尝试过一定次数以后再放弃尝试:

  if (responseCount(response) >= 3) {
    return null; // If we've failed 3 times, give up.
  }
  private int responseCount(Response response) {
    int result = 1;
    while ((response = response.priorResponse()) != null) {
      result++;
    }
    return result;
  }