ionic3+angular4 HttpClient封装优化

简介: 背景众所周知,angular4以后引入的HTTPClient为前端http请求带来了非常大的改进,它支持了与java类似的拦截器机制,通过拦截器,可以方便的对请求进行前置、后置及异常处理。

背景

众所周知,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

新增如下图所示的几个组件,组建的作用后面在说:


img_cd8a701ba7d5dfef03eeb1a0b20c981d.png
handler.png

包括:

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);
      }
    )
  }
img_99b6237b44c95d2ea6019d8bfd635876.png
image.png

总结

通过暴露三个可供继承重写的处理器类,可非常的在不同的场景下修改请求前后及异常时的处理逻辑,实现了公共组件与业务的解耦,方便了配置。

相关文章
|
4月前
|
JavaScript 前端开发 开发工具
Angular框架
Angular框架
39 0
|
6月前
|
JavaScript 前端开发 测试技术
angular框架怎么从0到1进行开发
angular框架怎么从0到1进行开发
37 0
|
6月前
|
自然语言处理 JavaScript 前端开发
angular-devkit 中 build-angular 包的作用
angular-devkit 中 build-angular 包的作用
90 0
|
6月前
|
前端开发 JavaScript API
关于 Angular 应用的 Bootstrap 过程
关于 Angular 应用的 Bootstrap 过程
31 0
|
6月前
|
网络协议 前端开发 API
关于 Angular HttpClient 的单例特性的思考
关于 Angular HttpClient 的单例特性的思考
30 0
|
监控 前端开发 JavaScript
Angular | 浅谈Angular错误处理方式
错误处理是编写代码经常遇见的并且必须处理的需求,很多时候处理异常的逻辑是为了避免程序的崩溃,之前《浅谈前端异常监控平台实现方案》介绍过异常跟踪,本文将简单介绍Angular处理异常的方式。
425 0
|
JavaScript 前端开发
Angular的HttpClient注入
Angular的HttpClient注入
Angular的HttpClient注入
Angular jasmine returnValue方法的实现原理
Angular jasmine returnValue方法的实现原理
66 0
Angular jasmine returnValue方法的实现原理