子產品中添加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 和類在很大程度上卻是不可變的。
這是有原因的:因為應用可能會重發請求,而攔截器鍊可能會多次處理同一個請求。如果請求是可變的,每次重試時的請求都可能和原始的請求不一樣。而不可變對象可以確定攔截器每次重試時處理的都是同一個請求。
在一種情況下類型安全體系無法在寫攔截器時提供保護 —— 請求體(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);
}
}