【问题标题】:Use a promise in Angular HttpClient Interceptor在 Angular HttpClient 拦截器中使用承诺
【发布时间】:2017-08-31 10:10:07
【问题描述】:

我可以在HttpInterceptor 中使用promise 吗?例如:

export class AuthInterceptor implements HttpInterceptor{
this.someService.someFunction()
    .then((data)=>{
       //do something with data and then
       return next.handle(req);
    });
}

为什么我需要这个?因为在向服务器发出请求之前,我需要获取一个令牌以添加到请求标头中。

我的拦截器:

@Injectable()
export class AuthInterceptor implements HttpInterceptor{

    constructor(private authService: AuthService){}

    intercept(req: HttpRequest<any>, next: HttpHandler) : Observable<HttpEvent<any>>{
        console.log('Intercepted!');
        // return next.handle(req);
        this.authService.getToken()
            .then((token)=>{
                console.log(token);
                const reqClone = req.clone({
                    headers: req.headers
                            .set('Authorization', 'Bearer ' + token)
                            .append('Content-Type', 'application/json')
                });
                console.log(reqClone);
                return next.handle(reqClone);
            })
            .catch((err)=>{
                console.log('error in interceptor' + err);
                return null;
            });
    }
}

请求:

this.http.post(this.baseURL + 'hero', data)
                    .subscribe(
                            (res: any) => {
                                console.log('Saved Successfully.');
                                console.log(res);
                            },
                            (err: any) => {
                                console.log('Save Error.' + err);
                            }
                        );

我面临的问题:

->我在承诺解决之前收到此错误。

You provided 'undefined' where a stream was expected. You can provide an Observable, Promise, Array, or Iterable.

承诺兑现,我得到了我的令牌,但在错误发生之后。

【问题讨论】:

  • 我刚刚在开发者工具下检查了我的 xhr 请求,那里没有“英雄”请求。所以,拦截器没有继续请求?

标签: angular rxjs es6-promise angular-httpclient angular-httpclient-interceptors


【解决方案1】:

更新:使用 rxjs@6.x

import { from, Observable } from 'rxjs';
import { switchMap } from 'rxjs/operators';

@Injectable()
export class AuthInterceptor implements HttpInterceptor {

    constructor(private authService: AuthService){}

    intercept(request: HttpRequest<any>, next: HttpHandler) : Observable<HttpEvent<any>>{
        return from(this.authService.getToken())
              .pipe(
                switchMap(token => {
                   const headers = request.headers
                            .set('Authorization', 'Bearer ' + token)
                            .append('Content-Type', 'application/json');
                   const requestClone = request.clone({
                     headers 
                    });
                  return next.handle(requestClone);
                })
               );
    }
}

原始答案

是的,你可以将需要的服务注入到拦截器的构造方法中,并在intercept的实现中检索值,创建一个新的更新的http请求并处理它。

我不擅长承诺,所以你可以尝试以下方法:

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

@Injectable()
export class AuthInterceptor implements HttpInterceptor{

    constructor(private authService: AuthService){}

    intercept(req: HttpRequest<any>, next: HttpHandler) : Observable<HttpEvent<any>>{
        return fromPromise(this.authService.getToken())
              .switchMap(token => {
                   const headers = req.headers
                            .set('Authorization', 'Bearer ' + token)
                            .append('Content-Type', 'application/json');
                   const reqClone = req.clone({
                     headers 
                    });
                  return next.handle(reqClone);
             });
    }
}

【讨论】:

  • 谢谢兄弟。我已经更新了这个问题。希望现在更清楚。
  • 它工作正常。非常感谢。是不是因为 getToken() 返回一个不可观察的承诺而不起作用? @Jota.Toledo
  • 拦截的返回类型必须是可观察的,我现在不知道如何使用承诺,这就是为什么我将承诺转化为可观察和应用的操作。我猜你的实现没有返回一个可观察的。如果我的回答对您有帮助,请选择它作为答案,以便您的问题被标记为已解决:)
  • 是的,我将我的函数更改为 observable 并且它现在可以在没有 fromPromise 的情况下工作。
  • @JeffreyWen 需要它们才能将令牌映射到内部可观察对象(next.handle 的结果)。这个想法基本上是将“令牌流”(只有1个事件)映射到一个新的。由于该方法的签名,不使用任何上述运算符都没有可行的方法。
【解决方案2】:

对于 RxJS 6+,我更新了 Jota.Toledo 的答案:

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

@Injectable()
export class AuthInterceptor implements HttpInterceptor{
constructor(private authService: AuthService){}
intercept(req: HttpRequest<any>, next: HttpHandler) : Observable<HttpEvent<any>>{
    return fromPromise(this.authService.getToken())
          .pipe(switchMap(token => {
               const headers = req.headers
                        .set('Authorization', 'Bearer ' + token)
                        .append('Content-Type', 'application/json');
               const reqClone = req.clone({
                 headers 
                });
              return next.handle(reqClone);
         }));
 }  
}

【讨论】:

  • 谢谢你,做得很好。我尝试了其他解决方案,但没有一个适用于 Angular 6+。
【解决方案3】:

轮到我了(感谢 Jota.Toledo 和 Capripio):

1) 将 "fromPromise" 切换为 "from" --> fromPromise does not exist on type Observable

2) 修复 'application/json' 引用

import { Observable, from } from 'rxjs';
import { switchMap } from 'rxjs/operators';

@Injectable()
export class AuthInterceptor implements HttpInterceptor {

  constructor(private authService: AuthService){}

  intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {

      return from(this.authService.getToken()).pipe(
        switchMap(token => {
            const headers = req.headers
                .set('Authorization', 'Bearer ' + token)
                .append('Content-Type', 'application/json');
            const reqClone = req.clone({
                headers
            });
            return next.handle(reqClone);
        }));
   }
}

我的 RxJs 版本:“6.2.2” 希望对您有所帮助!

【讨论】:

  • 为什么我们在将promise转换为observable后还要使用switchMap?
猜你喜欢
  • 2018-12-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-11-28
  • 1970-01-01
  • 2020-10-01
  • 1970-01-01
相关资源
最近更新 更多