令牌拦截器不再发送原始请求(Angular、Node.js)
Posted
技术标签:
【中文标题】令牌拦截器不再发送原始请求(Angular、Node.js)【英文标题】:Token interceptor does not send the original request again (Angular, Node.js) 【发布时间】:2020-03-15 04:54:25 【问题描述】:我正在尝试在我的 Angular 前端实现令牌拦截器,但我当前的实现存在一个问题。
我的拦截器如下所示:
intercept(request: HttpRequest<any>,next: HttpHandler): Observable<HttpEvent<any>>
if (request.headers.get("No-Auth") === "True")
return next.handle(request);
return next.handle(request).pipe(
catchError(error =>
if (error instanceof HttpErrorResponse && error.status === 401)
this.handle404Error(request, next);
else
return throwError(error);
)
);
及handle404Error函数:
handle404Error(request: HttpRequest<any>, next: HttpHandler)
if (!this.isRefreshing)
this.isRefreshing = true;
this.refreshTokenSubject.next(null);
return this.authService.refreshToken().subscribe(
(res: any) =>
if (Boolean(res) === true)
this.isRefreshing = false;
this.refreshTokenSubject.next(res);
return next.handle(request);
else
return this.authService.logout();
,
err =>
return this.authService.logout();
,
() =>
this.isRefreshing = false;
);
else
return this.refreshTokenSubject.pipe(
filter(res => res != null),
take(1),
switchMap(() =>
return next.handle(request);
)
);
当我进行 API 调用和服务器返回 404 时,我的拦截器将调用 /token
端点以获取新的 JWT。
请注意,我将 JWT 存储在服务器(内存中)的会话对象中,而在客户端我只有 sessionID 和刷新令牌作为 HttpOnly cookie。
问题是,当我进行 API 调用并且 JWT 无效时,它会设置新的 JWT,但它不会再次发送之前的请求。 (JWT过期后我必须按两次按钮才能获取数据)。
你有什么想法,如何实现这个逻辑?
感谢您的帮助。
【问题讨论】:
【参考方案1】:第一件事是不对的——你在拦截器中subscribe
,所以你得到了嵌套订阅,因为 Angular 在内部订阅了你的请求。
您真正想要的是从catchError
返回您的return next.handle(request);
。示例:
return next.handle(request).pipe(
catchError(error =>
if (error instanceof HttpErrorResponse && error.status === 401)
return this.handle404Error(request, next);
else
return throwError(error);
)
);
handle404Error(request: HttpRequest<any>, next: HttpHandler)
if (!this.isRefreshing)
this.isRefreshing = true;
this.refreshTokenSubject.next(null);
return this.authService.refreshToken().pipe(
mergeMap((res: any) =>
if (Boolean(res) === true)
this.isRefreshing = false;
this.refreshTokenSubject.next(res);
return next.handle(request);
else
/* return */ this.authService.logout();
return of(undefined) // added this because I dont know what this.authService.logout() returns. It must be an Observable
),
catchError((err) =>
/* return */ this.authService.logout();
return throwError(err);
))
else
return this.refreshTokenSubject.pipe(
filter(res => res != null),
take(1),
switchMap(() =>
return next.handle(request);
)
);
请注意,我没有检查任何错别字。我也丢弃了这个块:
() =>
this.isRefreshing = false;
如果您想在this.authService.refreshToken()
完成时执行它,您可以在mergeMap
和catchError
旁边添加finalize
运算符。
解释这里实际发生的事情很简单——你从intercept
方法返回一个 Observable。只需将所有 API 调用连接在一起,返回的流就会执行它们。
【讨论】:
它正在工作!但是有一个小问题 - 当我登录并调用受保护的路由时,它会返回一个结果,但是在令牌过期后我再次单击,调用 /token 不会开始,但是在我刷新页面并单击按钮后,它按我的预期工作。 嗯。也许它通过了这个声明 -request.headers.get("No-Auth") === "True"
。这里不能说太多。尝试放一些console.logs,看看它什么时候执行失败。以上是关于令牌拦截器不再发送原始请求(Angular、Node.js)的主要内容,如果未能解决你的问题,请参考以下文章