4

初衷

之前看到angular2正式发布了,过去看了下,感觉不错,于是入坑。
使用过程中想写一个像angular1那样的拦截器,一路坎坷啊

Angular1中的拦截器

.factory('HttpRequestInterceptor', ['$q', '$injector', 'ConfigService', 'DialogService', function($q, $injector, ConfigService, DialogService) {
    return {
        request: function(config) {
            if (config.method === 'POST') {
                config.timeout = 60000;
                if (config.data === undefined) {
                    config.data = {
                        nologin: 999
                    };
                } else {
                    config.data.nologin = 999;
                }
            }
            return config;
        },
        requestError: function(rejection) {
            DialogService.alert('发送请求失败,请检查网络');
            return $q.reject(rejection);
        },
        response: function(resp) {
            if (resp.data.code !== undefined && resp.data.code !== 0) {
                if (resp.data.code === 5003) {
                    var stateService = $injector.get('$state');
                    stateService.go('login', {}, {
                        reload: true
                    });
                } else {
                    DialogService.alert(resp.data.msg);
                }
            }
            return resp;
        },
        responseError: function(rejection) {
            console.log(rejection);
            if (rejection.status === 0) {
                DialogService.alert('请求响应错误,请检查网络');
            } else if (rejection.status === 500) {
                DialogService.alert('服务器出错');
            } else {
                DialogService.alert('请求失败,请检查网络');
            }
            return $q.reject(rejection);
        }
    };
}])

Angular2中没有提供,需要自己实现

去Stackoverflow上搜了好久,有相关内容是不错,但过时了。不过思路还是可以借鉴的。

尝试以下
第一篇链接
第二篇链接
第三篇

@Injectable()
export class CustomHttp extends Http {
  constructor(backend: ConnectionBackend, defaultOptions: RequestOptions) {
    super(backend, defaultOptions);
  }

  request(url: string | Request, options?: RequestOptionsArgs): Observable<Response> {
    console.log('request...');
    return super.request(url, options).catch(res => {
      // do something
    });        
  }

  get(url: string, options?: RequestOptionsArgs): Observable<Response> {
    console.log('get...');
    return super.get(url, options).catch(res => {
      // do something
    });
  }
}

app.module.ts里写法过时了

bootstrap(AppComponent, [HTTP_PROVIDERS,
    new Provider(Http, {
      useFactory: (backend: XHRBackend, defaultOptions: RequestOptions) => new CustomHttp(backend, defaultOptions),
      deps: [XHRBackend, RequestOptions]
  })
]);

按照上述代码,写法与angular2 r6不同,不知道怎么改。继续搜索,发现大部分写法都雷同,只是注入方式不同,后面看到了r6的注入方式,折腾几次,有了结果

自己的Intercept

customhttp.ts

import { Injectable } from '@angular/core';
import { Http, Request, RequestOptionsArgs, Response, RequestOptions, ConnectionBackend, Headers } from '@angular/http';
import 'rxjs/Rx';
import { Observable } from 'rxjs/Observable';
import { PubSubService } from './shared/pubsub.service';
@Injectable()
export class CustomHttp extends Http {
    _pubsub: PubSubService;
    constructor(backend: ConnectionBackend, defaultOptions: RequestOptions, pubsub: PubSubService) {
        super(backend, defaultOptions);
        this._pubsub = pubsub;
    }
    request(url: string | Request, options ? : RequestOptionsArgs): Observable < Response > {
        console.log("good");
        return this.intercept(super.request(url, options));
    }
    get(url: string, options ? : RequestOptionsArgs): Observable < Response > {
        return this.intercept(super.get(url, options));
    }
    post(url: string, body: string, options ? : RequestOptionsArgs): Observable < Response > {
        return this.intercept(super.post(url, body, this.getRequestOptionArgs(options)));
    }
    put(url: string, body: string, options ? : RequestOptionsArgs): Observable < Response > {
        return this.intercept(super.put(url, body, this.getRequestOptionArgs(options)));
    }
    delete(url: string, options ? : RequestOptionsArgs): Observable < Response > {
        return this.intercept(super.put(url, this.getRequestOptionArgs(options)));
    }
    getRequestOptionArgs(options ? : RequestOptionsArgs): RequestOptionsArgs {
        if (options == null) {
            options = new RequestOptions();
        }
        if (options.headers == null) {
            options.headers = new Headers();
        }
        options.headers.append('Content-Type', 'application/json');
        return options;
    }
    intercept(observable: Observable < Response > ): Observable < Response > {
        this._pubsub.beforeRequest.emit("beforeRequestEvent")
        observable.subscribe(null, (err) => {
            console.log('err');
            this._pubsub.afterRequest.emit("afterRequestEvent");
            this.handleError(err.status);
        }, () => {
            console.log('complete');
            this._pubsub.afterRequest.emit("afterRequestEvent");
        });
        return observable;
    }
    handleError(status) {
        if (status === 0) {
            this._pubsub.errorToast.emit("请求响应错误,请检查网络");
        } else if (status === 404) {
            this._pubsub.errorToast.emit("请求链接不存在,请联系管理员");
        } else if (status === 500) {
            this._pubsub.errorToast.emit("服务器出错,请稍后再试");
        } else {
            this._pubsub.errorToast.emit("未知错误,请检查网络");
        }
    }
}

pubsup.service.ts

import { Injectable } from '@angular/core';
import { Subject } from 'rxjs/Subject';
// 发布订阅事件, 继承自Subject, emit用于发射事件
class PubSubEvent extends Subject < String > {
    constructor() {
        super();
    }
    emit(value) { super.next(value); }
}
@Injectable()
export class PubSubService {
    beforeRequest: PubSubEvent;
    afterRequest: PubSubEvent;
    errorToast: PubSubEvent;
    successToast: PubSubEvent;
    showPupup: PubSubEvent;
    hidePupup: PubSubEvent;
    confirm: PubSubEvent;
    constructor() {
        this.beforeRequest = new PubSubEvent();
        this.afterRequest = new PubSubEvent();
        this.errorToast = new PubSubEvent();
        this.successToast = new PubSubEvent();
        this.showPupup = new PubSubEvent();
        this.hidePupup = new PubSubEvent();
        this.confirm = new PubSubEvent();
    }
}

app.module.ts

import { NgModule, Injectable } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { FormsModule } from '@angular/forms';
import { HttpModule, Http, XHRBackend, RequestOptions } from '@angular/http';
// import { InMemoryWebApiModule } from 'angular-in-memory-web-api';
import { HeroData } from './hero/hero-data';
import { routing } from './app.routing';
import { AppComponent } from './app.component';
import { CrisisCenterComponent } from './crisis/crisis-center.component';
import { MapComponent } from './map/map.component';
import { CustomHttp } from './customhttp';
import { MapService } from './map/map.service';

import { PubSubService } from './shared/pubsub.service';

import { PubSubComponent } from './shared/pubsub.component';
@NgModule({
    declarations: [
        AppComponent, CrisisCenterComponent, MapComponent, PubSubComponent
    ],
    imports: [
        BrowserModule,
        FormsModule,
        HttpModule,
        // InMemoryWebApiModule.forRoot(HeroData),
        routing
    ],
    providers: [
        MapService,
        PubSubService, {
            provide: Http,
            useFactory: (backend: XHRBackend, 
                defaultOptions: RequestOptions, 
                pubsub: PubSubService) => new CustomHttp(backend, defaultOptions, pubsub),
            deps: [XHRBackend, RequestOptions, PubSubService]
        }
    ],
    bootstrap: [AppComponent],
})
export class AppModule {}

最后是pubsup.component.ts,我是将loading, toast, pupup放在了一起
loading将在每个请求前显示,请求失败或结束隐藏
toast将在请求失败显示2秒钟,或者在其他组件里调用
pupup将在删除事件前提问,想放在delete api里自动显示并处理,但是没有实现
具体代码在我github:https://github.com/jiangbo201...

import { Component, Input } from '@angular/core';
import { Http } from '@angular/http';
import { PubSubService } from './pubsub.service';
@Component({
    selector: 'app-pubsub',
    templateUrl: './pubsub.component.html',
    styleUrls: ['./pubsub.component.css']
})
export class PubSubComponent {
    showloading = false;
    showPupub = false;
    showSuccessToast = false;
    showErrorToast = false;
    errorValue: any = "error";
    successValue: any = "success";
    _pubsub: PubSubService;
    constructor(public http: Http, public pubsub: PubSubService) {
        this._pubsub = pubsub;
    }
    cancel() {
            this.showPupub = false;
    }
    confirm() {
            this.showPupub = false;
            this._pubsub.confirm.emit("confirm");
    }
    ngOnInit() {
        
        this._pubsub.beforeRequest.subscribe(data => {
            console.log(data);
            this.showloading = true;
        });
        this._pubsub.afterRequest.subscribe(data => {
            console.log(data);
            this.showloading = false;
        });
        this._pubsub.errorToast.subscribe(data => {
            console.log(data);
            this.showErrorToast = true;
            this.errorValue = data;
            let that = this;
            // setTimeout(function() {
            //     console.log(this);
            //     that.showErrorToast = false;
            // }, 2000);
        });
        this._pubsub.successToast.subscribe(data => {
            console.log(data);
            this.showSuccessToast = true;
            this.successValue = data;
            let that = this;
            setTimeout(function() {
                that.showSuccessToast = false;
            }, 2000);

        });
        this._pubsub.showPupup.subscribe(data => {
            this.showPupub = true;
            console.log(data);
        });
        this._pubsub.hidePupup.subscribe(data => {
            console.log(data);
            this.showPupub = false;
        });
    }
}

最后,我想在每个删除aip里自动拦截,并弹出提示,如果确定删除就执行,如果放弃就return
但是不知道怎么阻塞执行,欢迎交流


紫气东来_姜波
28 声望3 粉丝