通过拦截,开发人员可以声明拦截器来检查和转换从应用程序到服务器的 HTTP 请求。 相同的拦截器还可以在返回应用程序的途中检查和转换服务器的响应。
多个拦截器共同形成请求/响应处理程序的前向和后向链。
拦截器可以以常规、标准的方式为每个 HTTP 请求/响应执行各种隐式任务,包括但不限于身份验证到日志记录。
如果没有拦截器的概念,开发人员将不得不为每个 HttpClient 方法调用显式地实现这些任务。
要实现拦截器,开发人员必须声明一个实现 HttpInterceptor
接口的 intercept()
方法的类。
下面是一个拦截器的实现,虽然拦截了 HTTP 请求之后,并未执行任何逻辑,只是简单的把请求传递给后向链:
import { Injectable } from '@angular/core';
import {
HttpEvent, HttpInterceptor, HttpHandler, HttpRequest
} from '@angular/common/http';
import { Observable } from 'rxjs';
/** Pass untouched request through to the next request handler. */
@Injectable()
export class NoopInterceptor implements HttpInterceptor {
intercept(req: HttpRequest, next: HttpHandler):
Observable> {
return next.handle(req);
}
}
intercept
方法将请求转换为最终返回 HTTP 响应的 Observable。
大多数拦截器在进入的过程中检查请求,并将可能更改的请求转发到实现 HttpHandler 接口的下一个对象的 handle() 方法。
与 intercept() 一样,handle() 方法将 HTTP 请求转换为 HttpEvents 的 Observable,最终包含服务器的响应。 intercept() 方法可以检查该 observable 并在将其返回给调用者之前对其进行更改,比如添加日志记录,字段过滤等等逻辑。
看个具体的例子:
上图是 SAP Spartacus UI SiteContextInterceptor 的实现,关键点如上图图例1和2所示:
- 使用
request.url.includes(this.occEndpoints.getBaseUrl()
判断当前请求 url 是否包含baseUrl
片段。 - 如果包含,使用
request.clone
, 给当前 HTTP 请求,添加 language 和 curr 参数。
这两个自动添加的参数,效果如下:
url:http://aaa/occ/v2/electronics-spa/currencies?lang=en&curr=USD
next
对象代表拦截器链中的下一个拦截器。链中的最后一个是 HttpClient 后端处理程序
,它将请求发送到服务器并接收服务器的响应。
大多数拦截器调用 next.handle() 以便请求流向下一个拦截器,最终流向后端处理程序。 拦截器可以跳过调用 next.handle(),使链短路,并返回自己的 Observable 和人工服务器响应。
这是 Express.js 等框架中常见的中间件模式。