import { Injectable } from '@angular/core'; import { HttpInterceptor, HttpRequest, HttpHandler, HttpEvent, HttpResponse, } from '@angular/common/http'; import { Observable, of, throwError, TimeoutError } from 'rxjs'; import { filter, mergeMap, catchError, timeout } from 'rxjs/operators'; import { NaConstant } from '@ng-arthur-mobile/common'; import { TranslateService } from '@ngx-translate/core'; import { NaHttpService } from '../na-http.service'; import { NaMessageService } from '@ng-arthur-mobile/core'; import { INaHttpConfig } from '../na-http-config'; import { NaHttpInterceptorPreparableHandler } from './na-http-interceptor-preparable'; /** * HTTP请求拦截处理 * * @export */ @Injectable() export class NaDefaultHttpClientInterceptor implements HttpInterceptor { private httpConfig: INaHttpConfig; constructor( protected translate: TranslateService, // 不能使用NaTranslateService,会产生循环引用 protected naHttpService: NaHttpService, private naMessageService: NaMessageService, private preparableHandler: NaHttpInterceptorPreparableHandler ) { } intercept(req: HttpRequest, next: HttpHandler): Observable> { // 获取请求中的`INaHttpConfig` this.httpConfig = this.naHttpService.httpConfig(req); const newReq = this.preparableHandler.handle(req); return this.interceptAfter(newReq, next.handle(newReq)).pipe( catchError((err: any) => { if (this.httpConfig.RTN_ERROR_PROMPT) { this.naMessageService.error(err[this.httpConfig.RTN_MSG]); } // TODO 可监控Http请求异常 return throwError(err); }) ); } interceptAfter(req: HttpRequest, resq: Observable>): Observable> { return resq.pipe( timeout(this.httpConfig.TIMEOUT), filter(value => value instanceof HttpResponse), mergeMap((value: any) => { const body: any = value.body; // responseType: 'blob' type='application/json' if (isBlob(body) && body.type && body.type.indexOf('application/json') > -1) { return new Promise>((resolve, reject) => { const blob = new Blob([body], {type: value.headers.get('Content-Type')}); const reader = new FileReader(); reader.onload = () => { reject(value.clone({ body: JSON.parse(reader.result.toString()) })); }; reader.readAsText(blob); }); } else { return throwError(value); } }), catchError((err: any) => { if (err instanceof TimeoutError) { // 系统超时 return throwError(this.errorObj('timeout')); } else if (err instanceof Error) { return throwError(err); } switch (err.status) { case 200: if (err instanceof HttpResponse) { const body: any = err.body; if (body) { const rtnCodeVal = body[this.httpConfig.RTN_CODE]; const rtnMsgVal = body[this.httpConfig.RTN_MSG]; // 存在错误码字段 if (rtnCodeVal && this.httpConfig.RTN_CODE_SUCCEED.indexOf(rtnCodeVal) < 0) { const params = new Object(); params[this.httpConfig.RTN_CODE] = rtnCodeVal; params[this.httpConfig.RTN_MSG] = rtnMsgVal; // 业务错误(错误码翻译 -> 系统自定义错误模版翻译 -> 错误信息翻译) let errorInfo = this.translate.instant([ rtnCodeVal || '', NaConstant.SYSTEM.TRANSACTION_FAILED_TEMPLATE, rtnMsgVal || '' ], params); if (errorInfo[rtnCodeVal] === rtnCodeVal) { if (errorInfo[NaConstant.SYSTEM.TRANSACTION_FAILED_TEMPLATE] === NaConstant.SYSTEM.TRANSACTION_FAILED_TEMPLATE) { errorInfo = errorInfo[rtnMsgVal]; } else { errorInfo = errorInfo[NaConstant.SYSTEM.TRANSACTION_FAILED_TEMPLATE]; } } else { errorInfo = errorInfo[rtnCodeVal]; } params[this.httpConfig.RTN_MSG] = errorInfo; return throwError(params); } else { return of(new HttpResponse(Object.assign(err, { body: body[this.httpConfig.RTN_DATA] }))); } } } return of(err); case 401: // 未登录状态码 // this.goTo('/login'); return throwError(this.errorObj(401)); default: return throwError(this.errorObj(err.status)); } }) ); } private errorObj(status: number | string) { const error = new Object(); if (!(status == null || status === 'undefined' || typeof(status) === 'undefined')) { const msg = this.translate.instant(`system.http.error.${status}`); error[this.httpConfig.RTN_MSG] = msg; error[this.httpConfig.RTN_CODE] = status; } return error; } } /** * Safely assert whether the given value is an ArrayBuffer. * * In some execution environments ArrayBuffer is not defined. */ export function isArrayBuffer(value: any): value is ArrayBuffer { return typeof ArrayBuffer !== 'undefined' && value instanceof ArrayBuffer; } /** * Safely assert whether the given value is a Blob. * * In some execution environments Blob is not defined. */ export function isBlob(value: any): value is Blob { return typeof Blob !== 'undefined' && value instanceof Blob; } /** * Safely assert whether the given value is a FormData instance. * * In some execution environments FormData is not defined. */ export function isFormData(value: any): value is FormData { return typeof FormData !== 'undefined' && value instanceof FormData; }