使用Angular全局处理401s [英] Handling 401s globally with Angular

查看:41
本文介绍了使用Angular全局处理401s的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在Angular 2项目中,我从返回Observable的服务中进行API调用.然后,调用代码将订阅此可观察的代码.例如:

In my Angular 2 project I make API calls from services that return an Observable. The calling code then subscribes to this observable. For example:

getCampaigns(): Observable<Campaign[]> {
    return this.http.get('/campaigns').map(res => res.json());
}

比方说服务器返回401.如何全局捕获此错误并重定向到登录页面/组件?

Let's say the server returns a 401. How can I catch this error globally and redirect to a login page/component?

谢谢.

这是我到目前为止所拥有的:

Here's what I have so far:

//boot.ts

import {Http, XHRBackend, RequestOptions} from 'angular2/http';
import {CustomHttp} from './customhttp';

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

//customhttp.ts

// customhttp.ts

import {Http, ConnectionBackend, Request, RequestOptions, RequestOptionsArgs, Response} from 'angular2/http';
import {Observable} from 'rxjs/Observable';

@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);        
    }

    get(url: string, options?: RequestOptionsArgs): Observable<Response> {

        console.log('get...');

        return super.get(url, options);
    }
}

我收到的错误消息是"backend.createConnection不是函数"

The error message I'm getting is "backend.createConnection is not a function"

推荐答案

说明

我发现的最佳解决方案是重写XHRBackend,以使HTTP响应状态401403导致特定的动作.

Description

The best solution I have found is to override the XHRBackend such that the HTTP response status 401 and 403 leads to a particular action.

如果您在Angular应用程序之外处理身份验证,则可以强制刷新当前页面,以便触发您的外部机制.我在下面的实现中详细介绍了此解决方案.

If you handle your authentication outside your Angular application you could force a refresh of the current page such that your external mechanism is triggered. I detail this solution in the implementation below.

您还可以转发到应用程序内部的组件,这样就不会重新加载Angular应用程序.

You could also forward to a component inside your application such that your Angular application is not reloaded.

感谢@mrgoos,这是angular 2.3.0+的简化解决方案,原因是在angular 2.3.0中进行了错误修复(请参见问题

Thanks to @mrgoos, here is a simplified solution for angular 2.3.0+ due to a bug fix in angular 2.3.0 (see issue https://github.com/angular/angular/issues/11606) extending directly the Http module.

import { Injectable } from '@angular/core';
import { Request, XHRBackend, RequestOptions, Response, Http, RequestOptionsArgs, Headers } from '@angular/http';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/catch';
import 'rxjs/add/observable/throw';


@Injectable()
export class AuthenticatedHttpService extends Http {

  constructor(backend: XHRBackend, defaultOptions: RequestOptions) {
    super(backend, defaultOptions);
  }

  request(url: string | Request, options?: RequestOptionsArgs): Observable<Response> {
    return super.request(url, options).catch((error: Response) => {
            if ((error.status === 401 || error.status === 403) && (window.location.href.match(/\?/g) || []).length < 2) {
                console.log('The authentication session expires or the user is not authorised. Force refresh of the current page.');
                window.location.href = window.location.href + '?' + new Date().getMilliseconds();
            }
            return Observable.throw(error);
        });
  }
}

模块文件现在仅包含以下提供程序.

The module file now only contains the following provider.

providers: [
    { provide: Http, useClass: AuthenticatedHttpService }
]

使用@mrgoos的以下要点详细介绍了使用路由器和外部身份验证服务的另一种解决方案.

Another solution using Router and an external authentication service is detailed in the following gist by @mrgoos.

以下实现适用于Angular 2.2.x FINALRxJS 5.0.0-beta.12.

如果返回HTTP代码401或403,它将重定向到当前页面(加上用于获取唯一URL并避免缓存的参数).

It redirects to the current page (plus a parameter to get a unique URL and avoid caching) if an HTTP code 401 or 403 is returned.

import { Request, XHRBackend, BrowserXhr, ResponseOptions, XSRFStrategy, Response } from '@angular/http';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/catch';
import 'rxjs/add/observable/throw';

export class AuthenticationConnectionBackend extends XHRBackend {

    constructor(_browserXhr: BrowserXhr, _baseResponseOptions: ResponseOptions, _xsrfStrategy: XSRFStrategy) {
        super(_browserXhr, _baseResponseOptions, _xsrfStrategy);
    }

    createConnection(request: Request) {
        let xhrConnection = super.createConnection(request);
        xhrConnection.response = xhrConnection.response.catch((error: Response) => {
            if ((error.status === 401 || error.status === 403) && (window.location.href.match(/\?/g) || []).length < 2) {
                console.log('The authentication session expires or the user is not authorised. Force refresh of the current page.');
                window.location.href = window.location.href + '?' + new Date().getMilliseconds();
            }
            return Observable.throw(error);
        });
        return xhrConnection;
    }

}

带有以下模块文件.

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { HttpModule, XHRBackend } from '@angular/http';
import { AppComponent } from './app.component';
import { AuthenticationConnectionBackend } from './authenticated-connection.backend';

@NgModule({
    bootstrap: [AppComponent],
    declarations: [
        AppComponent,
    ],
    entryComponents: [AppComponent],
    imports: [
        BrowserModule,
        CommonModule,
        HttpModule,
    ],
    providers: [
        { provide: XHRBackend, useClass: AuthenticationConnectionBackend },
    ],
})
export class AppModule {
}

这篇关于使用Angular全局处理401s的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆