HttpInterceptor的使用示例笔记
使用Angular的HttpInterceptor时的注意事项
网络拦截器
在发送请求之前或收到响应之后,可以添加通用处理的东西。
请查阅官方文件以获取详细信息(英文)。
https://angular.io/guide/http#advanced-usage
@ponday さんの記事は、日本語で書かれていて理解しやすいです。メモでは、Angular 4.3で追加されたHttpClientModuleについて述べられています。
共同请求设置
如果要更改标头或使用cookie,可以克隆并覆盖请求。
import { Injectable } from '@angular/core';
import { HttpEvent, HttpInterceptor, HttpHandler, HttpRequest } from '@angular/common/http';
import { Observable } from 'rxjs';
@Injectable()
export class RequestInterceptor implements HttpInterceptor {
private baseUrl = 'http://localhost:8080/sample-app';
constructor() { }
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
// '/api'から始まるリクエスト
if (request.url.match(/^\/api\//)) {
const req = request.clone({
url: `${this.baseUrl}/${request.url}`, // 接続先URL付加
withCredentials: true, // Cookie有効
setHeaders: { // ヘッダー書き換え
'Content-Type': 'application/json',
'X-Requested-With': 'XMLHttpRequest',
},
});
return next.handle(req);
}
return next.handle(request);
}
}
将测试与服务的URL设置分离,可以使测试编写更容易。
关于URL的更改,可以使用Proxy而不是HttpInterceptor。
https://angular.io/guide/build#proxying-to-a-backend-server
自动化显示错误消息
当无法每次手动捕捉错误并显示消息时。
import { Injectable } from '@angular/core';
import { HttpEvent, HttpInterceptor, HttpHandler, HttpRequest } from '@angular/common/http';
import { MatSnackBar } from '@angular/material';
import { Observable, throwError } from 'rxjs';
import { catchError } from 'rxjs/operators';
@Injectable()
export class ErrorInterceptor implements HttpInterceptor {
constructor(private toastService: MatSnackBar) { }
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
const req = request.clone();
return next.handle(req).pipe(
catchError(res => {
switch (res.status) {
case 400:
case 401:
case 403:
case 404:
case 500:
// {"errors":[{"message":"Sorry, that page does not exist","code":34}]}
const errors = JSON.parse(res.errors);
if (errors) {
errors.map(e => {
this.toastService.open(`${e.code}: ${e.message}`);
});
}
break;
default:
break;
}
return throwError(res);
})
);
}
}
自制面包也可以作为早餐选项。
自动显示进度条
由于手动控制进度条的显示/隐藏相对繁琐,因此我们可以通过拦截器自动化这个过程。
import { Injectable } from '@angular/core';
import { HttpEvent, HttpEventType, HttpInterceptor, HttpHandler, HttpRequest } from '@angular/common/http';
import { Observable } from 'rxjs';
import { tap, finalize } from 'rxjs/operators';
// サービスは別途用意
import { ProgressbarService} from './progressbar.service';
@Injectable()
export class ProgressbarInterceptor implements HttpInterceptor {
constructor(private progressbar: ProgressbarService) { }
// ↓参考
// https://github.com/MurhafSousli/ngx-progressbar/blob/master/src/services/interceptor.provider.ts
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
this.progressbar.show();
return next.handle(request).pipe(
//tap(event => {
// if (event.type === HttpEventType.UploadProgress) {
// const percent = Math.round(100 * event.loaded / event.total);
// this.progressbar.set(percent);
// }
//}),
finalize(() => {
this.progressbar.hide();
})
);
}
}
( ´ー`) .oO(虽然旋转器也可以做同样的事情,但屏幕可能会闪烁)※ 解决方法请参考评论。
将ISO-8601字符串转换为日期类型
如果返回的响应以字符串形式返回日期,直接使用getFullYear之类的函数是无法使用的,这样很麻烦…
在这种情况下,让我们在拦截器中提取字符串并自动将其转换为日期类型。
import { Injectable } from '@angular/core';
import { HttpEvent, HttpInterceptor, HttpHandler, HttpRequest, HttpResponse } from '@angular/common/http';
import { Observable } from 'rxjs';
import { tap } from 'rxjs/operators';
/**
* 元ネタは↓のAngularJS用インターセプタ
* https://gist.github.com/ScottGuymer/9994dae637bb2055d58b
*/
const ISO_8601 = /^\d{4,5}-\d\d-\d\dT\d\d:\d\d:\d\d(\.\d+)?(([+-]\d\d:\d\d)|Z)?$/i;
function convertDateStringsToDates(input: any) {
if (typeof input !== 'object') {
return input;
}
for (const key in input) {
if (!input.hasOwnProperty(key)) {
continue;
}
const value = input[key];
let match;
if (typeof value === 'string' && (match = value.match(ISO_8601))) {
const milliseconds = Date.parse(match[0]);
if (!isNaN(milliseconds)) {
input[key] = new Date(milliseconds);
}
} else if (typeof value === 'object') {
convertDateStringsToDates(value);
}
}
}
@Injectable()
export class DateInterceptor implements HttpInterceptor {
constructor() { }
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
const req = request.clone();
return next.handle(req).pipe(
tap(event => {
if (event instanceof HttpResponse) {
convertDateStringsToDates(event.body);
}
})
);
}
}
HttpInterceptor的好处在于它可以进行响应的处理!