模块中添加providers
@NgModule({
providers: [
HttpService,
{
provide: HTTP_INTERCEPTORS,
useClass: AuthInterceptor,//自定义拦截器的类名
multi: true,
},
],
})
注意multi: true
选项。这是必须的,因为它会告诉 Angular 这个 HTTP_INTERCEPTORS
表示的是一个数组,而不是单个的值。
事件
注意,intercept
和HttpHandler.handle
返回的可观察对象并不是Observable<HttpResponse<any>>
,而是Observable<HttpEvent<any>>
。 这是因为拦截器所工作的层级要低于 HttpClient
接口。单个请求会生成多个事件,比如表示上传和下载过程的事件。HttpResponse
类实际上本身也是一个事件,只是它的type
是HttpEventType.HttpResponseEvent
。
拦截器必须透传所有它不理解或不打算修改的事件。它不能过滤掉自己不准备处理的事件。很多拦截器只关心要发出的请求,而只简单的返回next
所返回的事件流,而不修改它。
**顺序
当我们在一个应用中提供了多个拦截器时,Angular 会按照你提供时的顺序应用它们(译注:即模块的providers
数组中列出的顺序)。
**不可变性
拦截器要检查和修改准备发出的请求和接收进来的响应。但是,你可能会惊奇的发现HttpRequest
和HttpResponse
类在很大程度上却是不可变的。
这是有原因的:因为应用可能会重发请求,而拦截器链可能会多次处理同一个请求。如果请求是可变的,每次重试时的请求都可能和原始的请求不一样。而不可变对象可以确保拦截器每次重试时处理的都是同一个请求。
在一种情况下类型安全体系无法在写拦截器时提供保护 —— 请求体(body)。在拦截器中修改请求体本应是无效的,但类型检查系统无法发现它。
如果确实需要修改请求体,我们就得自己复制它,修改这个复本,然后使用clone()
来复制这个请求,并使用这个新的请求体。
由于请求都是不可变的,所以不能直接修改它们。要想修改,就使用clone()
函数
创建拦截器
注意implements HttpInterceptor
import {Injectable} from '@angular/core';
import {HttpEvent, HttpInterceptor, HttpHandler, HttpRequest} from '@angular/common/http';
/**什么也不做,只是简单的转发请求而不做任何修改*/
@Injectable()
export class AuthInterceptor implements HttpInterceptor {
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
return next.handle(req);
}
}
//替换url
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
// This is a duplicate. It is exactly the same as the original.
const dupReq = req.clone();
// Change the URL and replace 'http://' with 'https://'
const secureReq = req.clone({url: req.url.replace('http://', 'https://')});
}
import {Injectable} from '@angular/core';
import {HttpEvent, HttpInterceptor, HttpHandler, HttpRequest} from '@angular/common/http';
/** 设置新的头,比如替换token*/
@Injectable()
export class AuthInterceptor implements HttpInterceptor {
constructor(private auth: AuthService) {}
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
// Get the auth header from the service.
const authHeader = this.auth.getAuthorizationHeader();
// Clone the request to add the new header.
const authReq = req.clone({headers: req.headers.set('Authorization', authHeader)});
// Pass on the cloned request instead of the original request.
return next.handle(authReq);
}
}
这种克隆一个请求并设置一组新的请求头的操作非常常见,因此有了一种快捷写法:
const authReq = req.clone({setHeaders: {Authorization: authHeader}});
如果需要注入service 使用如下方式
constructor(private injector: Injector) { }
this.httpService = this.injector.get(HttpService); // get HttpService within intercept
import {Injectable, Injector} from '@angular/core';
import {HttpEvent, HttpHandler, HttpInterceptor, HttpRequest} from '@angular/common/http';
import {HttpService} from "./http-service.service";
import {Observable} from "rxjs/Observable";
/**
* @description 拦截器,拦截所有http请求
* 目前实现功能:
* 1.请求的header中增加token
*/
@Injectable()
export class AuthInterceptor implements HttpInterceptor {
private httpService: HttpService;
constructor(private injector: Injector) {
}
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
this.httpService = this.injector.get(HttpService); // get HttpService within intercept
const authReq = request.clone({headers: request.headers.set('token', localStorage.getItem("token"))});
// Pass on the cloned request instead of the original request.
return next.handle(authReq);
}
}