| | |
| | | import { Injectable, Injector } from '@angular/core'; |
| | | import { Router } from '@angular/router'; |
| | | import { HttpInterceptor, HttpRequest, HttpHandler, |
| | | import { HttpInterceptor, HttpRequest, HttpHandler, HttpErrorResponse, |
| | | HttpSentEvent, HttpHeaderResponse, HttpProgressEvent, HttpResponse, HttpUserEvent, |
| | | } from '@angular/common/http'; |
| | | import { Observable } from 'rxjs/Observable'; |
| | | import { of } from 'rxjs/observable/of'; |
| | | import { ErrorObservable } from 'rxjs/observable/ErrorObservable'; |
| | | import { catchError } from 'rxjs/operators'; |
| | | import { map, mergeMap } from 'rxjs/operators'; |
| | | |
| | | import { environment } from '../../../environments/environment'; |
| | | import { mergeMap, catchError } from 'rxjs/operators'; |
| | | import { NzMessageService, NzModalService } from 'ng-zorro-antd'; |
| | | import { _HttpClient } from '@delon/theme'; |
| | | import { environment } from '@env/environment'; |
| | | import { LoginService } from '@business/services/http/login.service'; |
| | | import { Subject } from 'rxjs/Subject'; |
| | | import { error } from 'protractor'; |
| | | import { debug } from 'util'; |
| | | import {Location} from '@angular/common'; |
| | | |
| | | /** |
| | | * 默认HTTP拦截器,其注册细节见 `app.module.ts` |
| | | */ |
| | | @Injectable() |
| | | export class DefaultInterceptor implements HttpInterceptor { |
| | | constructor(private injector: Injector) {} |
| | | |
| | | private goLogin() { |
| | | const router = this.injector.get(Router); |
| | | this.injector.get(Router).navigate([ '/login' ]); |
| | | private unLoginHandle: Subject<HttpErrorResponse> = new Subject<HttpErrorResponse>(); |
| | | |
| | | constructor(private injector: Injector) { |
| | | let isExpireModelShow = false; |
| | | this.unLoginHandle.debounceTime(1000).delay(1000).filter( |
| | | () => !isExpireModelShow |
| | | ).subscribe( (event: HttpErrorResponse) => { |
| | | isExpireModelShow = true; |
| | | let errorMsg = ''; |
| | | if (!!event && !!event.error) { |
| | | const erroCode = !!event.error['errorCode'] ? Number.parseInt(event.error['errorCode']) : 0; |
| | | switch (erroCode) { |
| | | case 10: errorMsg = '未登录,请登录'; break; |
| | | case 11: errorMsg = '登录过期,请重新登录'; break; |
| | | case 12: errorMsg = '账号过期,请联系供应商'; break; |
| | | case 0: errorMsg = '服务器处于离线状态'; break; |
| | | default: errorMsg = '登录过期,请重新登录'; break; |
| | | } |
| | | }else { |
| | | errorMsg = '服务器处于离线状态'; |
| | | } |
| | | // 清空refresh信息,不再刷新 |
| | | this.loginService.clearRefreshToken(); |
| | | this.model.info({ |
| | | maskClosable: false, |
| | | title: errorMsg, |
| | | onOk: () => { |
| | | isExpireModelShow = false; |
| | | this.goTo('/passport/login'); |
| | | } |
| | | }); |
| | | }); |
| | | } |
| | | get loginService(): LoginService { |
| | | return this.injector.get<LoginService>(LoginService); |
| | | } |
| | | get msg(): NzMessageService { |
| | | return this.injector.get(NzMessageService); |
| | | } |
| | | get model(): NzModalService { |
| | | return this.injector.get(NzModalService); |
| | | } |
| | | private goTo(url: string) { |
| | | setTimeout(() => this.injector.get(Router).navigateByUrl(url)); |
| | | } |
| | | |
| | | intercept(req: HttpRequest<any>, next: HttpHandler): |
| | | Observable<HttpSentEvent | HttpHeaderResponse | HttpProgressEvent | HttpResponse<any> | HttpUserEvent<any>> { |
| | | private handleData(event: HttpResponse<any> | HttpErrorResponse): Observable<any> { |
| | | // 可能会因为 `throw` 导出无法执行 `_HttpClient` 的 `end()` 操作 |
| | | // this.injector.get(_HttpClient).end(); |
| | | // 业务处理:一些通用操作 |
| | | const status = !!event.status ? event.status : 401; |
| | | switch (status) { |
| | | case 200: |
| | | // 业务层级错误处理,以下假如响应体的 `status` 若不为 `0` 表示业务级异常 |
| | | // 并显示 `error_message` 内容 |
| | | |
| | | // TIPS:原TOKEN信息已交由 `@delon/auth` 处理 |
| | | // Document: http://ng-alain.com/docs/auth |
| | | // const body: any = event instanceof HttpResponse && event.body; |
| | | // if (body && body.status !== 0) { |
| | | // this.msg.error(body.error_message); |
| | | // // 继续抛出错误中断后续所有 Pipe、subscribe 操作,因此: |
| | | // // this.http.get('/').subscribe() 并不会触发 |
| | | // return ErrorObservable.throw(event); |
| | | // } |
| | | break; |
| | | case 401: // 未登录状态码 |
| | | // this.goTo('/passport/login'); |
| | | if (!this.isLoginPage) { |
| | | this.unLoginHandle.next(<HttpErrorResponse>event); |
| | | } |
| | | break; |
| | | case 403: |
| | | case 404: |
| | | case 500: |
| | | this.goTo(`/${event.status}`); |
| | | break; |
| | | } |
| | | // 这里不抛出错误 httpclient 无法捕捉 |
| | | if (event instanceof HttpErrorResponse) { |
| | | return ErrorObservable.create(event); |
| | | } else { |
| | | return of(event); |
| | | } |
| | | } |
| | | private get isLoginPage(): boolean { |
| | | return !!location && !!location.hash && location.hash.endsWith('login'); |
| | | } |
| | | intercept(req: HttpRequest<any>, next: HttpHandler): |
| | | Observable<HttpSentEvent | HttpHeaderResponse | HttpProgressEvent | HttpResponse<any> | HttpUserEvent<any>> { |
| | | // 统一加上服务端前缀 |
| | | let url = req.url; |
| | | if (!url.startsWith('https://') && !url.startsWith('http://') && !url.startsWith('assets')) { |
| | | url = environment.SERVER_URL + url; |
| | | // url = environment.SERVER_URL + url; |
| | | url = environment.SERVER_BASH_URL + url; |
| | | } |
| | | |
| | | const newReq = req.clone({ |
| | | url: url |
| | | }); |
| | | |
| | | return next.handle(newReq).pipe( |
| | | mergeMap((event: any) => { |
| | | mergeMap((event: any) => { |
| | | // 允许统一对请求错误处理,这是因为一个请求若是业务上错误的情况下其HTTP请求的状态是200的情况下需要 |
| | | if (event instanceof HttpResponse && event.status !== 200) { |
| | | // 业务处理:observer.error 会跳转至后面的 `catch` |
| | | // return ErrorObservable.create(event); |
| | | } |
| | | if (event instanceof HttpResponse && event.status === 200) { |
| | | // 刷新token的请求,不设置刷新 |
| | | if (!this.isLoginPage |
| | | && !!newReq.headers |
| | | && !newReq.headers.get('X-Refrsh-Token') |
| | | && !url.startsWith('assets')) { |
| | | this.loginService.refreshToken(); |
| | | } |
| | | return this.handleData(event); |
| | | } |
| | | // 若一切都正常,则后续操作 |
| | | return Observable.create(observer => observer.next(event)); |
| | | return of(event); |
| | | }), |
| | | catchError((res: HttpResponse<any>) => { |
| | | // 业务处理:一些通用操作 |
| | | switch (res.status) { |
| | | case 401: // 未登录状态码 |
| | | this.goLogin(); |
| | | break; |
| | | case 200: |
| | | // 业务层级错误处理 |
| | | console.log('业务错误'); |
| | | break; |
| | | case 404: |
| | | // 404 |
| | | break; |
| | | } |
| | | // 以错误的形式结束本次请求 |
| | | return ErrorObservable.create(event); |
| | | catchError((err: HttpErrorResponse) => { |
| | | return this.handleData(err); |
| | | }) |
| | | ); |
| | | } |