其他设置

其他设置

Header 设置

@Test
public void whenSetHeader_thenCorrect() throws IOException {
    Request request = new Request.Builder()
      .url(SAMPLE_URL)
      .addHeader("Content-Type", "application/json")
      .build();

    Call call = client.newCall(request);
    Response response = call.execute();
    response.close();
}

在此示例中,我们将看到如何在客户端本身上配置默认标头,而不是在每个请求上都设置默认标头。例如,如果要为每个请求设置内容类型 application/json,则需要为客户端设置拦截器。方法如下:

@Test
public void whenSetDefaultHeader_thenCorrect()
  throws IOException {

    OkHttpClient client = new OkHttpClient.Builder()
      .addInterceptor(
        new DefaultContentTypeInterceptor("application/json"))
      .build();

    Request request = new Request.Builder()
      .url(SAMPLE_URL)
      .build();

    Call call = client.newCall(request);
    Response response = call.execute();
    response.close();
}

这是 DefaultContentTypeInterceptor,它是 Interceptor 的扩展版本:

public class DefaultContentTypeInterceptor implements Interceptor {

  public Response intercept(Interceptor.Chain chain) throws IOException {
    Request originalRequest = chain.request();
    Request requestWithUserAgent = originalRequest
      .newBuilder()
      .header("Content-Type", contentType)
      .build();

    return chain.proceed(requestWithUserAgent);
  }
}

避免重定向

在此示例中,我们将看到如何配置 OkHttpClient 以停止跟随重定向。默认情况下,如果使用 HTTP 301 永久移动响应了 GET 请求,则会自动遵循重定向。在某些用例中,可能会很好,但是在某些用例中肯定是不需要的。为了实现此行为,在构建客户端时,需要将 followRedirects 设置为 false。请注意,响应将返回 HTTP 301 状态代码:

@Test
public void whenSetFollowRedirects_thenNotRedirected()
  throws IOException {

    OkHttpClient client = new OkHttpClient().newBuilder()
      .followRedirects(false)
      .build();

    Request request = new Request.Builder()
      .url("http://t.co/I5YYd9tddw")
      .build();

    Call call = client.newCall(request);
    Response response = call.execute();

    assertThat(response.code(), equalTo(301));
}

如果我们使用 true 参数打开重定向(或将其完全删除),则客户端将遵循重定向,并且测试将失败,因为返回码将为 HTTP 200。

超时与取消

当对方无法访问时,请使用超时使呼叫失败。网络故障可能是由于客户端连接问题,服务器可用性问题或两者之间的任何原因引起的。OkHttp 支持连接,读取和写入超时。在此示例中,我们以 1 秒的 readTimeout 构建客户端,而以 2 秒的延迟提供 URL:

@Test
public void whenSetRequestTimeout_thenFail()
  throws IOException {
    OkHttpClient client = new OkHttpClient.Builder()
      .readTimeout(1, TimeUnit.SECONDS)
      .build();

    Request request = new Request.Builder()
      .url(BASE_URL + "/delay/2")
      .build();

    Call call = client.newCall(request);
    Response response = call.execute();

    assertThat(response.code(), equalTo(200));
}

使用 Call.cancel() 立即停止正在进行的呼叫。如果线程当前正在写入请求或读取响应,则将抛出 IOException。当不再需要通话时,使用此功能可以节省网络。例如,当您的用户离开应用程序时:

@Test(expected = IOException.class)
public void whenCancelRequest_thenCorrect()
  throws IOException {
    ScheduledExecutorService executor
      = Executors.newScheduledThreadPool(1);

    Request request = new Request.Builder()
      .url(BASE_URL + "/delay/2")
      .build();

    int seconds = 1;
    long startNanos = System.nanoTime();

    Call call = client.newCall(request);

    executor.schedule(() -> {
        logger.debug("Canceling call: "
            + (System.nanoTime() - startNanos) / 1e9f);

        call.cancel();

        logger.debug("Canceled call: "
            + (System.nanoTime() - startNanos) / 1e9f);

    }, seconds, TimeUnit.SECONDS);

    logger.debug("Executing call: "
      + (System.nanoTime() - startNanos) / 1e9f);

    Response response = call.execute();

    logger.debug(Call was expected to fail, but completed: "
      + (System.nanoTime() - startNanos) / 1e9f, response);
}

响应缓存

要创建一个缓存,我们需要一个我们可以读写的缓存目录,以及对缓存大小的限制。客户端将使用它来缓存响应:

@Test
public void  whenSetResponseCache_thenCorrect()
  throws IOException {
    int cacheSize = 10 * 1024 * 1024;

    File cacheDirectory = new File("src/test/resources/cache");
    Cache cache = new Cache(cacheDirectory, cacheSize);

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

    Request request = new Request.Builder()
      .url("http://publicobject.com/helloworld.txt")
      .build();

    Response response1 = client.newCall(request).execute();
    logResponse(response1);

    Response response2 = client.newCall(request).execute();
    logResponse(response2);
}

启动测试后,第一个调用的响应将不会被缓存。对方法 cacheResponse 的调用将返回 null,而对方法 networkResponse 的调用将返回来自网络的响应。此外,缓存文件夹中将填充缓存文件。第二次调用执行将产生相反的效果,因为响应已经被缓存了。这意味着对 networkResponse 的调用将返回 null,而对 cacheResponse 的调用将返回来自缓存的响应。为了防止响应使用缓存,请使用 CacheControl.FORCE_NETWORK。若要阻止它使用网络,请使用 CacheControl.FORCE_CACHE。

上一页
下一页