Angular2:可观察订阅失败时如何重定向到登录页面?

Angular2 : How to redirect to the login page when observable subscription fails?

在文件auth-guard-service.ts中,为什么调用this.router.navigateByUrl('/ login') 不工作,同时打印警告消息?另一个文件中的另一个调用 (auth.service.ts) 工作正常。

auth-guard-service.ts

import { Injectable }          from '@angular/core';
import { CanActivate, Router } from '@angular/router';
import { Observable }          from 'rxjs';
import { Domain }              from 'domain';
import { AuthService }         from './auth.service';

@Injectable()
export class AuthGuardService implements CanActivate {
    private domain: Domain = new Domain();

    constructor(private router: Router) {}

    public canActivate(): Observable<boolean>|Promise<boolean>|boolean {
            return Observable.create(
                (observer) => {
                    this.domain.isauth()
                    .subscribe(
                        (res) => {
                            observer.next(true);
                        },
                        (err) => {
                            alert('You need to be authentificated to access this content');
                            // The call to navigateByUrl below does not work. To fix.
                            this.router.navigateByUrl('/login');
                        }
                    );
                }
            );
        }

auth.service.ts

import { Injectable }       from '@angular/core';
import { Router }           from '@angular/router';
import { Observable }       from 'rxjs';
import { Domain }           from 'domain';
import { ConfigService }    from './config.service';

@Injectable()
export class AuthService {
    private authObject: Observable<boolean>;
    private domain: Domain = new Domain();

    constructor(private router: Router) {}

    public login(login: string, password: string) : void {
        this.authObject = this.domain.auth(login, password);
        alert('Connecting... Please wait.');
        this.authObject.subscribe(
            (value) => {
                this.router.navigateByUrl('../view/dashboard');
            }
        );
    }

    public logout() : void {
        alert('Going to logout...');
        this.domain.logout();
        this.router.navigateByUrl('/login');
    }
}

app.routing.ts

import { ModuleWithProviders }  from '@angular/core';
import {
    Routes,
    RouterModule
}                               from '@angular/router';
import { LoginComponent }       from './login';
import {
    DashboardComponent,
    ViewComponent
}                               from './view';
import { AuthGuardService }     from './services';
const appRoutes: Routes = [
    {
        path: 'view',
        component: ViewComponent,
        canActivate: [AuthGuardService],
        children: [

            {
                path: 'dashboard',
                component: DashboardComponent
            }
            {
                path: '',
                redirectTo: 'dashboard',
                pathMatch: 'full'
            }
        ]
    },
    {
        path: 'login',
        component: LoginComponent
    }
    {
        path: '**',
        redirectTo: 'view'
    }
];

export const routing: ModuleWithProviders = RouterModule.forRoot(appRoutes, { useHash: true });

如果出现错误(如果用户未连接),我只想重定向到登录页面。

配置:Angular2

From angular documentation, "Always specify the complete absolute path when calling router's navigateByUrl method."

改用router.navigate

public canActivate(): Observable<boolean>|Promise<boolean>|boolean {
            return Observable.create(
                (observer) => {
                    this.domain.isauth()
                    .subscribe(
                        (res) => {
                            observer.next(true);
                        },
                        (err) => {
                            alert('You need to be authentificated to access this content');
                            // The call to navigateByUrl below does not work. To fix.
                            this.router.navigate(['/login']);
                        }
                    );
                }
            );
        }

简短的解决方案(没有 alert())是替换

this.router.navigate(['/login']);

来自

observer.next(this.router.navigate(['/login']));

或者,如果我想保留警报消息:

observer.next(false);
alert('You need to be authentificated to access this content');
this.router.navigateByUrl('/login');
  • 简短说明:

我们需要调用observer.next()来解锁回调栈并执行下一条回调指令;

  • 更详细的解释:

1) 如果你看代码,我订阅了一个观察者。在我出错的情况下,没有执行下一个回调的指令,所以堆栈可能是 'blocked'.

2) 根据 documentationnavigateByUrl() 是一个 Promise,它通过回调工作。所以navigateByUrl()可能需要前一个观察者先'unblocked',然后才依次执行。

3) 我们可能想知道为什么当两条指令在同一个块上时 alert() 没有任何问题打印出错误消息。原因可能是因为 Node 在不同的队列中执行打印堆栈(alert()、console.log() 等...)。

PS : 我不是Angular2/NodeJS/Callback/Promise/Observable的高手所以我不确定答案。如果您知道什么,请随时回答。 :)

这是我的回答。 subscribe 方法有 3 个参数,next、error 和 completed。订阅方法完成后重定向。在这种情况下,它将转到仪表板组件。

login() {
    this.authService.logIn(this.model).subscribe(
      next => {
        this.alertify.success('Logged in successfully');
      },
      error => {
        this.alertify.error(error);
      },
      () => {
        this.router.navigate(['/dashboard']);
      }
    );
  }