angular - 防止在 Angular 2 中多次调用访问令牌 API
问题描述
我正在 Angular 2 中开发一个应用程序,其中在不同时间段进行了多个 API 调用。
当访问令牌已过期并需要刷新时,就会出现问题。
对于每个 API 调用,我都会检查令牌状态。
当令牌过期时,将调用访问令牌 API,之后将执行实际的 API 调用。
当只有一个 API 调用时,此功能可以正常工作。
但是,当令牌过期时有 N 次 API 调用时,访问令牌 API 也会被调用 N 次。
这是目前的流程,
postRequest(url, body, header): Observable<Object> {
//Computation of Access token status
if (needToken) {
//Token header and body construction
return this.http.post(token_url, token_body, token_header).map(
(res: Response) => {
//Token Success
}
)
.flatMap(
success =>
this.http.post(url, body, header) //Actual API
)
.map((res: Response) => {
//Actual API Success
}
}
else {
return this.http.post(url, body, header).map(
(res: Response) => {
//API Success
}
)
}
}
如果在 Token 到期时有多个 API 调用,则执行 Token 标头和主体构造过程,甚至在 Token API 响应之前,其他 API 都会调用 Token API。
我尝试了上面的答案,但是当我们的函数返回 Observable 时,它表明 Promise 不能分配给 Observable。
我遇到了许多排队 API 请求的示例,但没有一个产生预期的结果。
如何在调用尚未响应的令牌 API 时将调用 API 排队,然后继续排队 API?
在这种情况下,当已经有访问令牌 API 的调用并返回时,等待的 API 应该转到 else 部分。
请帮我解决这个问题。谢谢你。
解决方案
根据您的需求 - 这是一个带有令牌管理上下文的 HttpInterceptor 实现片段:请注意,为了更好地分离我使用的关注点:
一个通用的 authService 负责令牌管理(从服务器询问、保存在缓存中等)。
行动经理 - 负责决定下一步去哪里。
import { Injectable } from '@angular/core';
import {HttpRequest,HttpHandler,HttpEvent,HttpInterceptor , HttpResponse , HttpErrorResponse} from '@angular/common/http';
import {Observable} from "rxjs";
import {tap} from "rxjs/operators";
import {HttpHandlerService} from "../../http-handler.service";
import {ActionsService} from "../../../actions/actions.service";
import {AuthService} from "../../../../core/auth/auth.service";
@Injectable({
providedIn: 'root'
})
export class TokenInterceptorService implements HttpInterceptor{
constructor(
private _actionsManager : ActionsService,
private _authService : AuthService
) {}
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
//Part 1 - adding headers - only for relevant apis
var accessToken = this._authService.getToken();
let authorizationHeader = accessToken ?
{'Authorization' : 'Bearer ' + accessToken , 'content-type' : 'application/json'}:
{'Authorization' : 'Basic ' + this._authService.getBasicToken() , 'content-type' : 'application/x-www-form-urlencoded'};
request = request.clone({
setHeaders: authorizationHeader
});
//Part 2 - handling request and responses
return next.handle(request).pipe(
tap(
(event: HttpEvent<any>) => {
if (event instanceof HttpResponse) {
// do stuff with response if you want
}
},
(err: any) => {
if (err instanceof HttpErrorResponse) {
if (err.status === 401 || err.status === 403) {
this._actionsManager.onEvent("unAuthorizedResponseFromServer");
}
}
}
)
);
}
}
推荐阅读
- python - 使用相同字符串的列表索引列表列表
- c++ - 如何在openCV中读取.tif浮点灰度图像
- c# - 如何上下移动虚拟listView项目?
- mongodb - 如何获取文档数组属性的串联列表?
- c# - 在 C# 接口中容纳来自 VB.Net 的参数化方法
- netsuite - NetSuite Suitescript 2.0 如何访问自定义项目选项记录?
- android - Kotlin Firebase onFailureListener 空异常
- reactjs - 如何更改 ag-grid 行数?
- angular - Angular中带有mat复选框的总和
- c# - Swagger 未加载 - 无法加载 API 定义:获取错误未定义