背景
众所周知,angular4以后引入的HTTPClient为前端http请求带来了非常大的改进,它支持了与java类似的拦截器机制,通过拦截器,可以方便的对请求进行前置、后置及异常处理。但如果我们需要在不同的项目中使用这个拦截器,且有不同的业务处理逻辑该怎么办呢?
步骤
1.编写HttpProvider
编写这个组件是为了提供一个简便的请求方法
1.1 生成HttpProvider组件
ionic g provider http
在providers/http文件夹下新增一个文件RequestMethods.ts用来存放支持的请求类型,内容如下:
export enum RequestMethods {
GET = 'GET',
POST = 'POST',
DELETE = 'DELETE',
OPTIONS = 'OPTIONS',
PATCH = 'PATCH',
TRACE = 'TRACE',
HEAD = 'HEAD'
}
1.2 修改http.ts内容
import {HttpClient} from '@angular/common/http';
import {Injectable} from '@angular/core';
import {Observable} from "rxjs";
import {RequestMethods} from "./RequestMethods";
import {Logger} from "../../common/logger/logger";
@Injectable()
export class HttpProvider {
constructor(private httpClient: HttpClient, private logger: Logger) {
logger.log("HttpProvider Init OK");
}
/**
* 发起一个get请求
* @param url
* @param paramMap
* @param header
*/
get(url: string, paramMap: {} = {}, header: {} = {}): Observable<object> {
return this.sendRequest(url, paramMap, RequestMethods.GET, header);
}
/**
* 发起一个post请求
* @param url
* @param paramMap
* @param header
*/
post(url: string, paramMap: {} = {}, header: {} = {}): Observable<object> {
return this.sendRequest(url, paramMap, RequestMethods.POST, header);
}
/**
* 发起一个delete请求
* @param url
* @param paramMap
* @param header
*/
delete(url: string, paramMap: {} = {}, header: {} = {}): Observable<object> {
return this.sendRequest(url, paramMap, RequestMethods.DELETE, header);
}
/**
* 发起一个options请求
* @param url
* @param paramMap
* @param header
*/
options(url: string, paramMap: {} = {}, header: {} = {}): Observable<object> {
return this.sendRequest(url, paramMap, RequestMethods.OPTIONS, header);
}
/**
* 发起一个trace请求
* @param url
* @param paramMap
* @param header
*/
trace(url: string, paramMap: {} = {}, header: {} = {}): Observable<object> {
return this.sendRequest(url, paramMap, RequestMethods.TRACE, header);
}
/**
* 发起一个head请求
* @param url
* @param paramMap
* @param header
* @constructor
*/
HEAD(url: string, paramMap: {} = {}, header: {} = {}): Observable<object> {
return this.sendRequest(url, paramMap, RequestMethods.HEAD, header);
}
/**
* 发起一个patch请求
* @param url
* @param paramMap
* @param header
*/
patch(url: string, paramMap: {} = {}, header: {} = {}): Observable<object> {
return this.sendRequest(url, paramMap, RequestMethods.PATCH, header);
}
/**
* 通用的请求方法,通过传入RequestMethods不同以发起不用类型的请求。
* 默认发起一个Get请求
* @param url 必传参数
* @param paramMap 默认为空
* @param method 默认GET
*/
request(url: string, paramMap: {} = {}, method: RequestMethods = RequestMethods.GET, header: {} = {}): Observable<object> {
return this.sendRequest(url, paramMap, method, header);
}
protected sendRequest(url: string, paramMap: any = {}, method: RequestMethods = RequestMethods.GET, header: {} = {}): Observable<object> {
this.logger.log("准备发起请求:");
this.logger.log("请求路径:", url);
this.logger.log("请求参数:", JSON.stringify(paramMap));
this.logger.log("请求方法:", method);
this.logger.log("请求头:", JSON.stringify(header));
return Observable.create(observer => {
this.httpClient.request(method, url, {params: paramMap, headers: header}).subscribe(
(res) => {
observer.next(res);
}
)
})
}
}
2. 编写拦截器
1. 新增interceptor组件
ionic g provider interceptor
新增如下图所示的几个组件,组建的作用后面在说:
包括:
DefaultRequestExceptionHandler.ts
DefaultRequestPreviewHandler.ts
DefaultRequestProcessedHandler.ts
RequestExceptionHandler.ts
RequestPreviewHandler.ts
RequestProcessedHandler.ts
2.修改interceptor.ts代码如下:
import {
HttpClient,
HttpEvent,
HttpHandler,
HttpInterceptor,
HttpRequest,
HttpResponse
} from '@angular/common/http';
import {Injectable} from '@angular/core';
import {Logger} from "../../../common/logger/logger";
import {catchError, tap} from "rxjs/operators";
import {Observable} from "rxjs";
import {RequestProcessedHandler} from "../handler/RequestProcessedHandler";
import {RequestPreviewHandler} from "../handler/RequestPreviewHandler";
import {RequestExceptionHandler} from "../handler/RequestExceptionHandler";
import {Constants} from "../../../common/Constants";
@Injectable()
export class LarkHttpInterceptor implements HttpInterceptor {
private timeoutMillis;
constructor(public http: HttpClient,
public logger: Logger,
private requestProcessedHandler: RequestProcessedHandler,
private requestPreviewHandler: RequestPreviewHandler,
private requestExceptionHandler: RequestExceptionHandler) {
logger.log('Hello InterceptorProvider Provider');
this.timeoutMillis = Constants.TIMEOUT_MILLS || 3000;
}
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
/**
* 请求前置处理
*/
this.requestPreviewHandler.handle(request);
return next.handle(request).timeout(this.timeoutMillis)
.pipe(
tap(event => {
if (event instanceof HttpResponse) {
/**
* 请求后置处理
*/
this.requestProcessedHandler.handle(event);
}
}, error => {
/**
* 请求异常处理
*/
this.requestExceptionHandler.handle(error);
}),
catchError((err: any) => {
this.requestExceptionHandler.handle(err);
return Observable.throw(err.message);
})
)
};
}
3.完善handler代码
RequestExceptionHandler(请求异常处理器类):
import {Injectable} from "@angular/core";
@Injectable()
export class RequestExceptionHandler {
handle(request: any): any {
return request;
};
}
RequestPreviewHandler(请求前置处理器类):
import {HttpRequest} from "@angular/common/http";
import {Injectable} from "@angular/core";
@Injectable()
export class RequestPreviewHandler {
handle(request: HttpRequest<any>): HttpRequest<any> {
return request;
};
}
RequestProcessedHandler(请求后置处理器类):
import {HttpResponse} from "@angular/common/http";
import {Injectable} from "@angular/core";
@Injectable()
export class RequestProcessedHandler {
handle(req: HttpResponse<any>): any {
return undefined;
};
}
DefaultRequestExceptionHandler(默认请求异常处理器实现类):
import {Injectable} from "@angular/core";
import {HttpResponse} from "@angular/common/http";
import {Logger} from "../../../../common/logger/logger";
import {RequestExceptionHandler} from "../RequestExceptionHandler";
import {TimeoutError} from "rxjs";
@Injectable()
export class DefaultRequestExceptionHandler extends RequestExceptionHandler {
constructor(private logger: Logger) {
super();
}
handle(res: any): any {
this.logger.warn("未注入自定义请求异常处理类,使用默认异常处理");
if (res instanceof HttpResponse) {
switch (res.status) {
case 200:
this.logger.log("业务异常")
break;
case 404:
this.logger.log("请求失败,未找到请求地址!");
case 500:
this.logger.log("请求失败,服务器出错,请稍后再试!");
case 0:
this.logger.log("请求失败,请求响应出错!");
default:
this.logger.log(res);
}
} else {
if(res instanceof TimeoutError){
this.logger.log("请求失败,超时TimeOut!");
}
this.logger.log(res);
}
return res;
}
}
DefaultRequestPreviewHandler(默认请求前置处理器实现类):
import {Injectable} from "@angular/core";
import {RequestPreviewHandler} from "../RequestPreviewHandler";
import {HttpRequest} from "@angular/common/http";
import {Logger} from "../../../../common/logger/logger";
@Injectable()
export class DefaultRequestPreviewHandler extends RequestPreviewHandler {
constructor(private logger: Logger) {
super();
}
handle(request: HttpRequest<any>): HttpRequest<any> {
this.logger.warn("未注入自定义请求前置处理类,使用默认前置处理");
return request;
}
}
DefaultRequestProcessedHandler(默认请求后置处理器实现类):
import {HttpResponse} from "@angular/common/http";
import {Logger} from "../../../../common/logger/logger";
import {RequestProcessedHandler} from "../RequestProcessedHandler";
import {Injectable} from "@angular/core";
@Injectable()
export class DefaultRequestProcessedHandler extends RequestProcessedHandler {
constructor(private logger: Logger) {
super();
}
handle(req: HttpResponse<any>): any {
this.logger.warn("未注入自定义请求后置处理类,使用默认后置处理");
this.logger.log(req);
return req.body;
}
}
4.在app.module.ts中配置注入
import {DefaultRequestProcessedHandler} from "../providers/http/handler/default-handler/DefaultRequestProcessedHandler";
import {LarkHttpInterceptor} from "../providers/http/interceptor/interceptor";
import {RequestProcessedHandler} from "../providers/http/handler/RequestProcessedHandler";
import {RequestPreviewHandler} from "../providers/http/handler/RequestPreviewHandler";
import {DefaultRequestPreviewHandler} from "../providers/http/handler/default-handler/DefaultRequestPreviewHandler";
import {RequestExceptionHandler} from "../providers/http/handler/RequestExceptionHandler";
import {DefaultRequestExceptionHandler} from "../providers/http/handler/default-handler/DefaultRequestExceptionHandler";
......
providers: [
StatusBar,
SplashScreen,
{provide: RequestPreviewHandler, useClass: DefaultRequestPreviewHandler},
{provide: RequestProcessedHandler, useClass: DefaultRequestProcessedHandler},
{provide: RequestExceptionHandler, useClass: DefaultRequestExceptionHandler},
{provide: HTTP_INTERCEPTORS, useClass: LarkHttpInterceptor, multi: true},
HttpProvider,
]
5. 发起请求:
constructor(public navCtrl: NavController, public http: HttpProvider, public logger: Logger) {
this.http.get("https://www.sojson.com/api/qqmusic/8446666/json").subscribe(
(info) => {
this.logger.log("请求成功", info);
}
)
}
总结
通过暴露三个可供继承重写的处理器类,可非常的在不同的场景下修改请求前后及异常时的处理逻辑,实现了公共组件与业务的解耦,方便了配置。