【问题标题】:Wait for http inside Guard on Angular 5在 Angular 5 上等待 Guard 内部的 http
【发布时间】:2018-04-22 23:34:55
【问题描述】:

我在 Angular 应用程序上使用 Guard 来解析初始关键数据。在 Angular 的第 4 版上,我是这样处理的:

// app.routing.ts
routing = [{
    path: '', component: AppComponent, canActivate: [ResolveGuard],
}];

// resolve.guard.ts
@Injectable()
export class ResolveGuard implements CanActivate {
    constructor(
        private _api: ApiService,
    ) { }

    canActivate(): any {
        return this._api.apiGet('my/url').map(response) => {
            if ( response.status === 'success') {
                // Consume data here
                return true;
            }

            return false;
        }).first();
    }
}

由于Http on Angular 5 的新版本不再使用.map() 属性,所以这不起作用。

如果我将.map() 更改为.subscribe(),它不会引发任何错误,但应用程序永远不会正确解析。另一方面,使用.first() 和/或.map() 会引发一些错误,正如在此版本中所预期的那样。

在这种情况下我该怎么办?

只有在加载初始数据时才需要激活该路由。


编辑以添加有关apiGet 函数的信息:

constructor(private _http: HttpClient) {}

public apiGet(url: string): any {
    return this._http
        .get(this.apiUrl + url)
        .catch(this.handleError.bind(this));
}

【问题讨论】:

  • 不再使用 map() 方法是什么意思? o.O
  • 请添加你的apiGet方法的定义,否则很难说你能做什么
  • @Jota.Toledo 我的意思是说新的 Http 客户端模块不再需要它(如果我理解正确的话)。另外,我用 apiGet 函数更新了问题,但它是调用 http 函数的服务。
  • 你检查过答案了吗?

标签: angular rxjs angular-router angular-httpclient angular-router-guards


【解决方案1】:

所以,第一件事是:尽可能避免使用any,特别是当你知道哪种类型属于哪里时。

export interface FooInterface {
  status: string;
  fooString : string;
  fooNumber : number;
}

首先我会以干净的方式定义服务的接口,然后我会重构守卫类。

更新答案rxjs 6.x

import { throwError, Observable } from 'rxjs';
import { catchError } from 'rxjs/operators';

@Injectable()
export class FooService {
   constructor(private _http: HttpClient) {}

   public apiGet(url: string): Observable<FooInterface> {
    return this._http
        .get<FooInterface>(this.apiUrl + url)
        .pipe(
          catchError(error => {
             // do general error handling if necessary and throw
            throwError(error);
           })
        );
  }
}

守卫类:

import { of, Observable } from 'rxjs';
import { map, catchError } from 'rxjs/operators';

@Injectable()
export class ResolveGuard implements CanActivate {
constructor(
    private fooService: FooService ,
) { }

canActivate(): Observable<boolean> {
    return this.fooService.apiGet('my/url')
       .pipe(
         map(response => response.status === 'success'),
         catchError(error => of(false))
       );
}

原始答案rxjs 5.x

import { _throw } from 'rxjs/observable/throw':

constructor(private _http: HttpClient) {}

public apiGet(url: string): Observable<FooInterface> {
    return this._http
        .get<FooInterface>(this.apiUrl + url)
        .catch(error => {
          // do general error handling if necessary and throw
          _throw(error);
       });
}

守卫类:

import { of } from 'rxjs/observable/of';

@Injectable()
export class ResolveGuard implements CanActivate {
constructor(
    private _api: ApiService,
) { }

canActivate(): Observable<boolean> {
    return this._api.apiGet('my/url')
       .map(response => {
          let val = false;
          if ( response.status === 'success') {
                // Consume data here
                val = true;
          }
          return val;
        }).catch(error => {
          // consume the error maybe?
          of(false)
        });
}

【讨论】:

  • 嗨,你能解释一下你的代码吗,比如为什么使用 map 代替 subscribe ,使用 of() 和其他类似的东西。
  • 在内部,angular 订阅了守卫返回的 observable。出于这个原因,守卫唯一需要做的就是将 api 服务返回的 observabletransform 转换为布尔流。在源 observable 的情况下,HTTP 请求失败,守卫仍然必须返回一个流,而不是抛出。这就是我使用of 将错误映射到新流的原因。 @charle819
  • 哦,好吧,但是在各种情况下,如果我们尝试从 AuthGuard 内部调用一个方法(基本上是调用一个服务),AuthGuard 似乎不会等待服务的响应,你能说出原因吗?
  • “各种情况”太含糊了。取决于你实际在做什么。随意打开一个新问题并标记我。
【解决方案2】:

只需导入 map 运算符,它就会起作用:

import { Observable } "rxjs/Observable"; 
import "rxjs/add/operator/map"; 

 canActivate(): Observable<boolean>{
        return this._api.apiGet('my/url').map(response => {
            if ( response.status === 'success') {
                // Consume data here
                return true;
            }
            return false;
        });
    }

【讨论】:

  • 为什么 first() 放在最后?
  • 您的代码只是在 Observable 导入中缺少“来自”,但它正在工作。此外,在Angular 5 release blog post 上,它说我应该像这样导入地图:import { map } from 'rxjs/operators'; 但它不起作用。当我导入旧方法时它才起作用。也许这就是我的代码出了什么问题(?)
  • @celsomtrindade 仔细阅读文章完整,关于如何使用'rxjs/operators'中的元素有区别
猜你喜欢
  • 2019-01-22
  • 2019-01-08
  • 1970-01-01
  • 2018-11-13
  • 2019-02-18
  • 1970-01-01
  • 2017-06-10
  • 2020-02-01
  • 2021-04-15
相关资源
最近更新 更多