1.概述
通常,在我们的Web应用程序中管理HTTP请求的请求和响应周期时,我们需要一种方法来利用此链。通常情况下,这是我们履行我们的要求,或我们的servlet代码完成后,只需之前添加一些自定义的行为。
OkHttp是适用于Android和Java应用程序的高效HTTP和HTTP / 2客户端。在以前的教程中,我们研究了如何使用OkHttp的基础知识。
在本教程中,我们将学习有关如何拦截HTTP请求和响应对象的所有信息。
2.拦截器
顾名思义,拦截器是可插入的Java组件,在将请求发送到我们的应用程序代码之前,我们可以使用它们来拦截和处理请求。
同样,它们为我们提供了一种强大的机制,可让我们在容器将响应发送回客户端之前处理服务器响应。
当我们想要更改HTTP请求中的某些内容(例如添加新的控件标头,更改请求的正文或仅生成日志以帮助我们进行调试)时,此功能特别有用。
使用拦截器的另一个不错的功能是,它们使我们可以将通用功能封装在一个地方。假设我们要在全局上对所有请求和响应对象应用某种逻辑,例如错误处理。
将这种逻辑放入拦截器至少有两个优点:
- 我们只需要将此代码维护在一个地方,而不是所有端点
- 发出的每个请求都以相同的方式处理错误
最后,我们还可以监视,重写和重试来自拦截器的调用。
3.常用用法
当显然可以选择接受器时,其他一些常见任务包括:
- 记录请求参数和其他有用信息
- 向我们的请求添加身份验证和授权标头
- 格式化我们的请求和响应主体
- 压缩发送给客户端的响应数据
- 通过添加一些Cookie或额外的标头信息来更改我们的响应标头
我们将在后面的部分中看到一些使用这些示例的示例。
4.依赖关系
当然,我们需要将标准的okhttp
依赖项添加到我们的pom.xml
:
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>4.9.1</version>
</dependency>
我们还需要另一个依赖项专门用于我们的测试。让我们添加OkHttp mockwebserver
网络服务器工件:
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>mockwebserver</artifactId>
<version>4.9.1</version>
<scope>test</scope>
</dependency>
现在我们已经配置了所有必需的依赖项,我们可以继续编写第一个拦截器。
5.定义一个简单的日志拦截器
让我们从定义我们自己的拦截器开始。为了简单起见,我们的拦截器将记录请求标头和请求URL:
public class SimpleLoggingInterceptor implements Interceptor {
private static final Logger LOGGER = LoggerFactory.getLogger(SimpleLoggingInterceptor.class);
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
LOGGER.info("Intercepted headers: {} from URL: {}", request.headers(), request.url());
return chain.proceed(request);
}
}
如我们所见,要创建拦截器,我们需要做的就是从Interceptor
接口继承,该接口具有一个强制方法intercept(Chain chain)
。然后,我们可以继续使用自己的实现重写此方法。
首先,在打印出标题和请求URL之前,我们通过调用chain.request()
重要的是要注意,每个拦截器实现的关键部分是对chain.proceed(request)
的调用。
这种简单的方法是我们发出信号要打入我们的应用程序代码,并生成响应来满足请求的地方。
5.1合并一起使用
要真正利用此拦截器,我们要做的就是在构建OkHttpClient
addInterceptor
方法,它应该可以正常工作:
OkHttpClient client = new OkHttpClient.Builder()
.addInterceptor(new SimpleLoggingInterceptor())
.build();
我们可以继续为需要的addInterceptor
数量的拦截器调用addInterceptor方法。只要记住,它们将按照添加的顺序被调用。
5.2。测试拦截器
现在,我们定义了第一个拦截器;让我们继续编写我们的第一个集成测试:
@Rule
public MockWebServer server = new MockWebServer();
@Test
public void givenSimpleLogginInterceptor_whenRequestSent_thenHeadersLogged() throws IOException {
server.enqueue(new MockResponse().setBody("Hello Baeldung Readers!"));
OkHttpClient client = new OkHttpClient.Builder()
.addInterceptor(new SimpleLoggingInterceptor())
.build();
Request request = new Request.Builder()
.url(server.url("/greeting"))
.header("User-Agent", "A Baeldung Reader")
.build();
try (Response response = client.newCall(request).execute()) {
assertEquals("Response code should be: ", 200, response.code());
assertEquals("Body should be: ", "Hello Baeldung Readers!", response.body().string());
}
}
首先,我们使用OkHttp MockWebServer
JUnit规则。
这是一个轻量级的,可编写脚本的Web服务器,用于测试HTTP客户端,我们将使用它们来测试拦截器。通过使用此规则,我们将为每个集成测试创建服务器的干净实例。
考虑到这一点,现在让我们来看一下测试的关键部分:
- 首先,我们设置了一个模拟响应,该响应在主体中包含一条简单消息
- 然后,我们构建
OkHttpClient
并配置SimpleLoggingInterceptor
- 接下来,我们使用一个
User-Agent
标头设置要发送的请求 - 最后一步是发送请求并验证响应代码和收到的正文是否符合预期
5.3。运行测试
最后,当我们运行测试时,我们将看到记录的HTTP User-Agent
标头:
16:07:02.644 [main] INFO cboiSimpleLoggingInterceptor - Intercepted headers: User-Agent: A Baeldung Reader
from URL: http://localhost:54769/greeting
5.4使用内置的HttpLoggingInterceptor
尽管我们的日志记录拦截器很好地演示了如何定义拦截器,但是值得一提的是OkHttp具有内置的日志记录器,我们可以利用它。
为了使用此记录器,我们需要一个额外的Maven依赖项:
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>logging-interceptor</artifactId>
<version>4.9.1</version>
</dependency>
然后,我们可以继续实例化我们的记录器,并定义我们感兴趣的记录级别:
HttpLoggingInterceptor logger = new HttpLoggingInterceptor();
logger.setLevel(HttpLoggingInterceptor.Level.HEADERS);
在此示例中,我们仅对看到标题感兴趣。
6.添加自定义响应标题
现在,我们了解了创建拦截器的基础知识。现在让我们看一下另一个典型的用例,其中我们修改了一个HTTP响应头。
如果我们要添加自己的专有应用程序HTTP标头或重写从服务器返回的标头之一,则这可能很有用:
public class CacheControlResponeInterceptor implements Interceptor {
@Override
public Response intercept(Chain chain) throws IOException {
Response response = chain.proceed(chain.request());
return response.newBuilder()
.header("Cache-Control", "no-store")
.build();
}
}
和以前一样,我们调用chain.proceed
方法,但是这次没有预先使用request对象。当响应返回时,我们使用它来创建新响应并将Cache-Control
标头设置为no-store
。
实际上,我们不太希望每次都告诉浏览器从服务器中拉出,但是我们可以使用这种方法在响应中设置任何标头。
7.使用拦截器进行错误处理
如前所述,我们还可以使用拦截器来封装一些我们想全局应用于所有请求和响应对象的逻辑,例如错误处理。
假设我们想在响应不是HTTP 200响应时返回带有状态和消息的轻量级JSON响应。
考虑到这一点,我们将从定义一个简单的bean来保存错误消息和状态代码开始:
public class ErrorMessage {
private final int status;
private final String detail;
public ErrorMessage(int status, String detail) {
this.status = status;
this.detail = detail;
}
// Getters and setters
}
接下来,我们将创建拦截器:
public class ErrorResponseInterceptor implements Interceptor {
public static final MediaType APPLICATION_JSON = MediaType.get("application/json; charset=utf-8");
@Override
public Response intercept(Chain chain) throws IOException {
Response response = chain.proceed(chain.request());
if (!response.isSuccessful()) {
Gson gson = new Gson();
String body = gson.toJson(
new ErrorMessage(response.code(), "The response from the server was not OK"));
ResponseBody responseBody = ResponseBody.create(body, APPLICATION_JSON);
return response.newBuilder().body(responseBody).build();
}
return response;
}
}
很简单,我们的拦截器会检查响应是否成功,是否创建了一个包含响应代码和一条简单消息的JSON响应:
{
"status": 500,
"detail": "The response from the server was not OK"
}
8.网络拦截器
到目前为止,我们所介绍的拦截器就是OkHttp所谓的应用程序拦截器。但是,OkHttp还支持另一种称为网络拦截器的拦截器。
我们可以按照与前面所述完全相同的方式定义网络拦截器。**但是,在创建HTTP客户端实例时,我们需要调用addNetworkInterceptor
**方法:
OkHttpClient client = new OkHttpClient.Builder()
.addNetworkInterceptor(new SimpleLoggingInterceptor())
.build();
应用程序和网络接收器之间的一些重要区别包括:
- 即使拦截器提供了HTTP响应,应用程序拦截器也总是被调用一次
- 网络拦截器挂接到网络级别,是放置重试逻辑的理想位置
- 同样,当我们的逻辑不依赖于响应的实际内容时,我们应该考虑使用网络拦截器
- 使用网络拦截器可以使我们访问承载请求的连接,包括用于连接到Web服务器的IP地址和TLS配置之类的信息。
- 应用程序拦截器无需担心中间响应,例如重定向和重试
- 相反,如果我们有适当的重定向,则可能会多次调用网络拦截器
如我们所见,这两种选择都有各自的优点。因此,这实际上取决于我们将为之选择的特定用例。
但是,应用程序拦截器通常会很好地完成工作。
9.结论
在本文中,我们学习了有关如何使用OkHttp创建拦截器的所有信息。首先,我们首先说明什么是拦截器,以及如何定义一个简单的日志记录拦截器来检查我们的HTTP请求标头。
然后,我们了解了如何在响应对像中设置标头以及其他主体。最后,我们快速了解了应用程序拦截器和网络拦截器之间的一些区别。
0 评论