繁体   English   中英

在Angular 2中拦截HTTP响应

[英]Intercepting HTTP Response in Angular 2

我正在使用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);
 }
}

我以为我可以在@ngModuleproviders部分执行以下@ngModule

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

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

但这只是让我失去了一堆模块错误:

ERROR in [default] C:/WebConnectionProjects/AlbumViewer/Web/src/app/app.module.ts:64:10
Argument of type '{ imports: (ModuleWithProviders | typeof BrowserModule)[]; declarations: (typeof AlbumList | type...' is not assignable to parameter of type 'NgModuleMetadataType'.
  Types of property 'providers' are incompatible.
  Type '(typeof ConnectionBackend | typeof Album | typeof Artist | typeof Track | typeof AppConfiguration...' is not assignable to type 'Provider[]'.
  Type 'typeof ConnectionBackend | typeof Album | typeof Artist | typeof Track | typeof AppConfiguration ...' is not assignable to type 'Provider'.
  Type 'typeof ConnectionBackend' is not assignable to type 'Provider'.
  Type 'typeof ConnectionBackend' is not assignable to type 'FactoryProvider'.
  Property 'provide' is missing in type 'typeof ConnectionBackend'.

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

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

我的方法不同。 我创建了一个与内置Http交互的HTTPService类,而不是扩展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的Http 相反,我调用HttpService.get()

我采取了不同的方法并扩展了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 ],
                }
            ],
        };
    }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM