在Angular 2中拦截HTTP响应

时间:2016-09-12 00:29:52

标签: angular angular2-services

我正在使用RC6,而我正试图弄清楚如何在整个应用程序中捕获HTTP错误 - 特别是auth错误。

有很多帖子描述了如何使用自定义类扩展Http类,但我不确定如何完全注册新类,因为语法随着最近的更改而出现ngModule更改。

这是班级(添加了所有相关的导入):

@Injectable()
export class InterceptedHttp 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);
 }

 get(url: string, options?: RequestOptionsArgs): Observable<Response> {
  console.log('get...');
  return super.get(url,options);
 }
}

我以为我可以在providers的{​​{1}}部分执行以下操作:

@ngModule

但是这只会让我失去一些模块错误:

 imports: [ HttpModule, ... ],
 providers: [
    ... 

    InterceptedHttp,
    {provide: Http, useClass: InterceptedHttp },
    ConnectionBackend
 ],

删除添加的行,一切正常。

那么,如何注册自定义Http类?

2 个答案:

答案 0 :(得分:3)

我对此的看法不同。我创建了一个HTTPService类,它与内置的Http进行交互,而不是扩展Http

@Injectable()
export class HttpService{
    constructor(private http:Http){}

    /** Wrapper for Http.get() that intercepts requests and responses */
    get(url:string, options?:RequestOptions):Observable<any>{

        //pre-screen the request (eg: to add authorization token)
        options = this.screenRequest(options);

        return this.http.get(url,options)
            .map(res => res.json()) //my back-end return a JSON. Unwrap it
            .do(res => this.screenResponse(res)) // intercept response
            .catch(res => this.handleError(res));// server returned error status
    }

    /** similar to the above; a wrapper for Http.post() */
    post(url:string, body:string ,options?:RequestOptions):Observable<any>{}

    /** edits options before the request is made. Adds auth token to headers.*/
    screenOptions(options?:RequestOptions):RequestOptions{}

    /** Called with server's response. Saves auth token from the server */
    screenResponse(jsonResponse:any){}

    /** Called when server returns a 400-500 response code */
    handleError(response:Response){}        
}

所以我的代码永远不会直接调用Angular&#39; Http。相反,我打电话给HttpService.get()

答案 1 :(得分:2)

我采用了不同的方法并扩展了XHRBackend,到目前为止它已经处理了我的所有需求。

export class CoreXHRBackend extends XHRBackend {

    constructor(xhr:BrowserXhr, opts:ResponseOptions, strat:XSRFStrategy, public alerts:Alerts) {
        super(xhr, opts, strat);
    }

    createConnection(request:Request) {
        let xhr = super.createConnection(request);

        /**
         * Global error handler for http requests
         */
        xhr.response = xhr.response.catch((error:Response) => {

            if (error.status === 401 && window.location.pathname !== '/') {
                this.alerts.clear().flash('You are not authorized to access that page', 'danger');
                window.location.href = '/';
            }

            if (error.status === 404) {
                this.alerts.clear().error('Sorry, we couldn\'t find that...');
            }

            // Validation errors or other list of errors
            if (error.status === 422) {
                var messages = error.json();
                Object.keys(messages).map(k => this.alerts.error(messages[k]));
            }

            if (error.status === 500) {
                this.alerts.clear().error('Sorry Something Went Wrong, Try Again Later!');
            }

            return Observable.throw(error);
        });

        return xhr;
    }
}

我还需要注入我的自定义警报服务,构造函数不能注射,所以我在我的模块中处理了这个...

export class CoreModule {
    static forRoot(): ModuleWithProviders {
        return {
            ngModule: CoreModule,
            providers: [
                Alerts,
                {
                    provide: XHRBackend,
                    useFactory: (xhr, opts, strat, alerts) => {
                        return new CoreXHRBackend(xhr, opts, strat, alerts);
                    },
                    deps: [ BrowserXhr, ResponseOptions, XSRFStrategy, Alerts ],
                }
            ],
        };
    }
}