AngularJS 2 Observable - xhr失败重定向

时间:2016-03-03 00:55:26

标签: angular rxjs observable

我目前正在编写一个Angular 2网络应用程序,我想创建一个'拦截器'来检测xhr请求是否因authorization (401)而被拒绝。

如果发生这种情况,我希望我的应用程序重定向到登录页面,例如。

我不确定如何继续这样的行为,任何想法,最佳实践将不胜感激。

3 个答案:

答案 0 :(得分:1)

您可以执行以下操作:

export class CustomHTTPConnection implements Connection
{
}

请注意,Connection是一个抽象类,因此您必须从头开始构建它。

另一种方法是采用接近同一事物的Auth0方式。 https://github.com/auth0/angular2-jwt/blob/master/angular2-jwt.ts然后您可以在那里添加401错误的处理,并将它们发送到401上的登录页面。

或者,如果用户未登录,您可以对所有路线施加限制,如果他们尝试访问您网站的其他部分,则始终会重定向到登录。

创建一个新的路由器插座,其作用与另一个相同,但会检查它们是否通过activate(指令:ComponentInstruction)登录。您还可以添加publicRoutes,表示您可以在不登录的情况下访问某些页面。**警告您不能这样做,这样使用HashLocationStrategy,因为它没有正确记录this.parentRouter.lastNavigationAttempt。 / p>

import {Directive, Attribute, ElementRef, DynamicComponentLoader} from 'angular2/core';
import {Router, RouterOutlet, ComponentInstruction} from 'angular2/router';
import {Login} from '../login/login.component';

@Directive({
  selector: 'router-outlet'
})
export class LoggedInRouterOutlet extends RouterOutlet {
  publicRoutes: any;
  private parentRouter: Router;

  constructor(_elementRef: ElementRef, _loader: DynamicComponentLoader,
              _parentRouter: Router, @Attribute('name') nameAttr: string) {
    super(_elementRef, _loader, _parentRouter, nameAttr);

    this.parentRouter = _parentRouter;
    this.publicRoutes = {
    };
  }

  activate(instruction: ComponentInstruction) {
    var url = this.parentRouter.lastNavigationAttempt;
    console.log(url);
    if (!this.publicRoutes[url] && !localStorage.getItem('jwt')) {//Public Routes does not work with Hash Location Strategy, need to come up with something else.
      // todo: redirect to Login, may be there is a better way?
      this.parentRouter.navigate(['Login']);
    }
    return super.activate(instruction);
  }
}

然后就像你通常那样打电话:

import {LoggedInRouterOutlet} from './utility/LoggedInOutlets';

@Component({
    selector: 'my-app',
    directives: [LoggedInRouterOutlet],
    template: `<div class="container">
                   <router-outlet></router-outlet>
               </div>`
})

现在这将检​​查他们是否每次进入另一条路线时都会登录,这样做很酷的事情是我不必每次都ping服务器,虽然不安全但不建议使用生产,它可以为您节省一些时间开发!

答案 1 :(得分:1)

扩展<router-outlet>是一种方法,但我发现Auth0示例存在一些缺陷(如果由于错误而使用自定义路由器插座的自定义管道,也会导致Angular 2中断)。

我找到了Brandon Roberts on a GitHub issue提出的另一种方法,基本上是使用@CanActivate装饰器。我们的想法是使用@CanActivate注释您的路由组件,其中包含当前用户是否可以访问给定路由的逻辑。

import {Component, View} from 'angular2/core';
import {CanActivate} from 'angular2/router';
import {Page} from './Page';
import {isLoggedIn} from './is-logged-in';

@Component({
  ...
})
@CanActivate((next: ComponentInstruction, previous: ComponentInstruction) => {
  return isLoggedIn(next, previous);
})
export class Protected {
}

正如您所看到的,@CanActivate采用上一个ComponentInstruction的函数以及您即将过渡的下一个函数。

  

ComponentInstruction是一个对象,它表示给定组件的路由数据,坦率地说,是有关要调用的上一个和下一个路由的信息。

目前只有一个“问题”,就是你不能将依赖注入CanActivate函数。这就是为什么你必须应用一种解决方法,即在某处存储你的注射器(理想情况下是根注射器)。

// app-injector.ts
import {Injector} from 'angular2/core';

let appInjectorRef: Injector;
export const appInjector = (injector?: Injector):Injector => {
    if (injector) {
      appInjectorRef = injector;
    }

    return appInjectorRef;
};

然后,在Angular 2引导逻辑所在的main.ts文件中......

// main.ts
import {bootstrap} from 'angular2/platform/browser';
...
import {App} from './app';
import {appInjector} from './app-injector';

bootstrap(App, [
  ...
]).then((appRef: ComponentRef) => {
  // store a reference to the application injector
  appInjector(appRef.injector);
});

...你让那个类将根注入器传递给它。您现在可以通过简单地导入它来从其他地方获取对您的注射器的引用,如

import {appInjector} from './app-injector';

let injector = appInjector();
let someDep = injector.get(...);

这种方法的好处是它更加明显和灵活。扩展<router-outlet>隐藏在幕后。

无论如何,您可以在Brandon的Plunker中找到上述的实时代码示例:http://plnkr.co/edit/SF8gsYN1SvmUbkosHjqQ?p=preview

答案 2 :(得分:0)

一种方法可以是扩展HTTP对象以拦截错误:

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

并按如下所述进行注册:

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

如果此级别出现401错误,您可以根据您在此CustomHttp类上注入的当前路由器将用户重定向到登录页面。