【问题标题】:Using a promise to return a request object from an HTTP interceptor使用 Promise 从 HTTP 拦截器返回请求对象
【发布时间】:2019-07-16 00:16:53
【问题描述】:

这几个小时我一直在摸不着头脑,我希望有人可以帮助我并指导我。所以,我正在开发一个 Angular 7 应用程序身份验证模块。要求之一是开发 HTTP 拦截器以添加授权 (JWT) 令牌并处理所有错误消息。

我正在使用 NPM 包来处理令牌的本地存储。这个包使用 set 和 get 方法来存储和返回一个 promise 而不是令牌的实际值。

现在,我的问题在于我的拦截器功能,如下所示。我试图评论我卡住的地方。

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

    // Trying to get the token here but this returns a promise
    // this.token is a service for managing storage and retrieving of tokens
    const token = this.token.getToken();

    // If token is got, set it in the header
    // But when i console log, i see [object promise] other than the token
    if (token) {
        request = request.clone({
            headers: request.headers.set('Authorization', 'Bearer ' + token)
        });
    }

    return next.handle(request).pipe(catchError(err => {
        // Logs out the user if 401 error
        if (err.status === 401) {
            this.token.remove()
                .then(() => {
                    this.auth.changeAuthStatus(false);
                    this.router.navigateByUrl('/login');
                });
        }

        // Returns the error message for the user to see
        // for example in an alert
        const error = err.error.message || err.statusText;
        return throwError(error);
    }));
}

我希望我已经很好地解释了这个问题。我曾尝试在拦截器函数之前使用async,但我得到一个红色的讨厌的错误,说TS1055: Type 'typeof Observable' is not a valid async function return type in ES5/ES3 because it does not refer to a Promise-compatible constructor value.   Types of parameters 'subscribe' and 'executor' are incompatible.

对于解决此问题的任何帮助,我将不胜感激。

谢谢!

【问题讨论】:

  • 你把token存到localstorage了吗?
  • @ZarnaBorda 我实际上正在使用 ionic,我想坚持使用默认返回承诺的存储包。我设法使用下面的废弃代码解决了这个问题。

标签: angular angular7 angular-http-interceptors


【解决方案1】:

要将异步处理合并到您的拦截器中,您希望将您的 Promise 提升为可观察对象,并 switchMap 您的可观察对象一起返回正确的请求:

import { from as observableFrom } from "rxjs";
import { switchMap } from "rxjs/operators";

intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    return observableFrom(this.token.getToken()).pipe(
        switchMap(token => {

            // do something with your promise-returned token here

            return next.handle(request).pipe(catchError(err => {
                // Logs out the user if 401 error
                if (err.status === 401) {
                    this.token.remove()
                        .then(() => {
                            this.auth.changeAuthStatus(false);
                            this.router.navigateByUrl('/login');
                        });
                }

                // Returns the error message for the user to see
                // for example in an alert
                const error = err.error.message || err.statusText;
                return throwError(error);
            }));
        })
    );
}

尚未直接测试此代码,因此对于任何拼写错误,我深表歉意,但它应该可以让您到达您想去的地方。

1) 使用from 将您的承诺推广到可观察对象

2) 使用 switchMap 链接您的 observables

我注意到您实际上并没有使用示例中返回的令牌,您可以在 switchMap 中接收承诺结果的函数中执行此操作

【讨论】:

  • 非常感谢。我最终对switchMap 进行了更多研究,发现它可以做一些令人惊奇的事情。一切都按预期工作!我正要放弃 Promise 和 Observables。你值得喝啤酒。干杯!
  • @derelict 你能解释为什么switchMap 而不是flatMap/mergeMap 吗? AFAIK,只要this.token.getToken() 只触发一次,它就会产生相同的结果,对吧?谢谢。
  • @sevenlops -- 有一段时间了。我认为我的想法是停止来自每个请求令牌的重复 http 请求;我从一个需要考虑的项目中举出了我的例子。因为getToken() 承诺应该只有一个响应,所以它们中的任何一个都是相同的。
【解决方案2】:

尝试直接从本地存储中获取令牌。为此,当您获取令牌时,使用令牌服务方法将该令牌存储到本地存储。

试试下面的代码:

token.service.ts

setToken(token) {
    localStorage.setItem('app-token', JSON.stringify(token));
}

getToken() {
    return JSON.parse(localStorage.getItem('app-token'));
}

拦截器代码

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

//This token is retrieved from local storage
const token = this.token.getToken();

// If token is got, set it in the header
// But when i console log, i see [object promise] other than the token
if (token) {
    request = request.clone({
        headers: request.headers.set('Authorization', 'Bearer ' + token)
    });
}

return next.handle(request).pipe(catchError(err => {
    // Logs out the user if 401 error
    if (err.status === 401) {
        this.token.remove()
            .then(() => {
                this.auth.changeAuthStatus(false);
                this.router.navigateByUrl('/login');
            });
    }

    // Returns the error message for the user to see
    // for example in an alert
    const error = err.error.message || err.statusText;
    return throwError(error);
}));
}

【讨论】:

    猜你喜欢
    • 2017-06-19
    • 2023-03-18
    • 1970-01-01
    • 2014-04-01
    • 1970-01-01
    • 2018-12-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多