HttpInterceptor
桩引,是Angular提供用于在全局應(yīng)用程序級(jí)別處理HTTP請(qǐng)求的內(nèi)置工具已慢,攔截并處理HttpRequest或HttpResponse入挣。攔截器在實(shí)戰(zhàn)中的作用有很多移宅,比如:統(tǒng)一配置網(wǎng)關(guān)地址虎忌,設(shè)置Http請(qǐng)求頭泡徙,處理Http請(qǐng)求返回?cái)?shù)據(jù),統(tǒng)一錯(cuò)誤處理等都是常見的需求膜蠢。
這里介紹三種不同的攔截器的實(shí)現(xiàn):
- 處理Http請(qǐng)求頭 (Http Request Headers)
- 處理Http響應(yīng) (Http Response)
- Http錯(cuò)誤處理 (Http Error)
先看一下攔截器的最基本的實(shí)現(xiàn)
import { Injectable } from '@angular/core';
import { HttpInterceptor, HttpEvent, HttpResponse, HttpRequest, HttpHandler } from '@angular/common/http';
import { Observable } from 'rxjs';
@Injectable()
export class CustomInterceptor implements HttpInterceptor {
public intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
return next.handle(req);
}
}
要?jiǎng)?chuàng)建一個(gè)自定義攔截器堪藐,我們需要實(shí)現(xiàn) @angular/common/http
中提供的 HttpInterceptor
。每一個(gè)通過HttpClient
調(diào)用的請(qǐng)求挑围,都會(huì)觸發(fā)攔截器調(diào)用intercept()
方法礁竞。當(dāng)調(diào)用intercept()方法時(shí),Angular會(huì)向httpRequest對(duì)象傳遞一個(gè)引用對(duì)象杉辙。然后我們可以根據(jù)需要修改它模捂。完成處理之后,調(diào)用next蜘矢,將更新后的請(qǐng)求返回到應(yīng)用程序狂男。
我們需要將攔截器其注冊(cè)為一個(gè)多提供者,因?yàn)樵谝粋€(gè)應(yīng)用程序中可以運(yùn)行多個(gè)攔截器硼端。注:攔截器將只攔截使用HttpClient服務(wù)發(fā)出的請(qǐng)求并淋。
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http';
import { CustomInterceptor } from './custom.interceptor';
import { AppComponent } from './app.component';
@NgModule({
imports: [BrowserModule, HttpClientModule ],
declarations: [ AppComponent ],
bootstrap: [ AppComponent ],
providers: [
{ provide: HTTP_INTERCEPTORS, useClass: CustomInterceptor, multi: true }
]
})
export class AppModule { }
下面根據(jù)我們的需求實(shí)現(xiàn)我們的Http攔截器
處理Http請(qǐng)求頭 (Http Request Headers Interceptor)
通常我們處理Http請(qǐng)求的時(shí)候,需要在請(qǐng)求頭中加入一些身份驗(yàn)證信息珍昨,比如token
,我們可以通過攔截器為所有的請(qǐng)求加上token
信息
import { Injectable } from '@angular/core';
import { HttpInterceptor, HttpRequest, HttpHandler, HttpEvent } from '@angular/common/http';
import { Observable } from 'rxjs';
@Injectable()
export class HeaderInterceptor implements HttpInterceptor {
public intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
return next.handle(this.addToken(req, 'bearer my token'));
}
private addToken(req: HttpRequest<any>, token: string): HttpRequest<any> {
return req.clone({ setHeaders: { Authorization: token } });
}
}
創(chuàng)建一個(gè)Http請(qǐng)求县耽,來驗(yàn)證我們添加的token
constructor(private httpClient: HttpClient) {
this.httpClient.get('/assets/json/data.json').subscribe(ret => {
// TODO:
});
}
處理Http響應(yīng) (Http Response Interceptor)
當(dāng)我們需要對(duì)Http請(qǐng)求的返回?cái)?shù)據(jù)進(jìn)行統(tǒng)一處理時(shí),例如镣典,當(dāng)返回結(jié)果是如下格式兔毙,status
為200的時(shí)候,我們只保留我們需要的信息兄春。
{
"data": [
{ "id": 1, "name": "趙錢" },
{ "id": 2, "name": "孫李" },
{ "id": 3, "name": "周吳" },
{ "id": 4, "name": "鄭王" }
],
"requestDatetime": "1949-10-01"
}
根據(jù)上面的需求澎剥,來新增一個(gè)ResponseHandlerInterceptor
import { HttpEvent, HttpHandler, HttpInterceptor, HttpRequest, HttpResponse } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs';
import { filter, map } from 'rxjs/operators';
@Injectable()
export class ResponseHandlerInterceptor implements HttpInterceptor {
public intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
return next.handle(req).pipe(
filter(event => event instanceof HttpResponse && event.status === 200),
map((event: HttpResponse<any>) => event.clone({ body: event.body.data }))
);
}
}
上面的代碼中,當(dāng)返回的數(shù)據(jù)狀態(tài)是200
的時(shí)候赶舆,我們只返回body中我們需要的data數(shù)據(jù)哑姚。
Http錯(cuò)誤處理 (Http Error Interceptor)
在Http請(qǐng)求中,我們需要對(duì)錯(cuò)誤情況進(jìn)行統(tǒng)一處理芜茵,這時(shí)候叙量,我們也可以借助攔截器實(shí)現(xiàn)(錯(cuò)誤提示或者重試等)。
import { HttpEvent, HttpHandler, HttpInterceptor, HttpRequest } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { Observable, throwError } from 'rxjs';
import { catchError, retry } from 'rxjs/operators';
@Injectable()
export class ErrorHandlerInterceptor implements HttpInterceptor {
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
return next.handle(req).pipe(
catchError(error => {
switch (error.status) {
case 401: // Unauthorized
// todo
break;
case 403: // Forbidden
// todo
break;
default:
// todo
return throwError(error);
}
}),
retry(3)
);
}
}
在上面的ErrorHandlerInterceptor
攔截器會(huì)攔截http請(qǐng)求的錯(cuò)誤情況九串,我們可以根據(jù)具體的業(yè)務(wù)需求進(jìn)行處理绞佩,也可以通過retry(3)
進(jìn)行錯(cuò)誤重試(3表示重試三次)
當(dāng)然寺鸥,創(chuàng)建的時(shí)候要記得配置注入
···
providers: [
{
provide: HTTP_INTERCEPTORS,
useClass: HeaderInterceptor,
multi: true
},
{
provide: HTTP_INTERCEPTORS,
useClass: ResponseHandlerInterceptor,
multi: true
},
{
provide: HTTP_INTERCEPTORS,
useClass: ErrorHandlerInterceptor,
multi: true
}
]
···