fengxiang
2018-07-06 8ac3a87733b421c1f1cb3b691f946c05bdae02df
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
import { Injectable, Injector } from '@angular/core';
import { Router } from '@angular/router';
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 { 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 {
    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));
    }
 
    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` 内容
 
                // 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_BASH_URL + url;
        }
 
        const newReq = req.clone({
            url: url
        });
        return next.handle(newReq).pipe(
                    mergeMap((event: any) => {                        
                        // 允许统一对请求错误处理,这是因为一个请求若是业务上错误的情况下其HTTP请求的状态是200的情况下需要
                        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 of(event);
                    }),
                    catchError((err: HttpErrorResponse) => {
                        return this.handleData(err);
                    })
                );
    }
}