我正在尝试处理来自 interceptor 的 401 响应使用 httpClientModule .认证基于JWT,有accessToken和refreshToken。如果 accessToken 已过期,我需要请求 api 使用 refreshToken 获取新的。我想在应该生成新 token 时阻止请求,获取一个新 token ,然后使用附加的新 accessToken 发出请求。
这样,从拦截器发出http请求的最佳方法是什么?
我的拦截器:
@Injectable()
export class JwtService implements HttpInterceptor {
constructor(public inj: Injector){}
intercept(req : HttpRequest<any>, next : HttpHandler) : Observable<HttpEvent<any>> {
if ( this.shouldGenerateNewAccessToken(req.url) ){
const auth = this.inj.get(AuthService);
auth.getNewAccessToken().then( token => {
if (token){
const headers = { 'Authorization' : token };
const clone = req.clone( { setHeaders : headers } );
return next.handle(clone);
} else { return next.handle(req); }
}, error => {
return next.handle(req);
});
}
else {
if (APP_CONFIG['accessToken']){
const headers = { 'Authorization' : APP_CONFIG['accessToken'] };
const clone = req.clone( { setHeaders : headers });
return next.handle(clone);
} else {
return next.handle(req);
}
}
}
shouldGenerateNewAccessToken(url : string) : Boolean {
let lastupdate = APP_CONFIG['accessTokenTimestamp'];
let now = new Date().getTime();
// Let say the token expires after 5s
if ((now - lastupdate) > 5000 && APP_CONFIG['refreshToken'] && url != APP_CONFIG['apiEndPont']+'getaccesstoken'){
return true;
}
else
return false;
}
授权逻辑
getNewAccessToken() : Promise<any>{
return new Promise( (resolve, reject)=>{
this.http.post(this.api+ 'getaccesstoken', JSON.stringify({refreshToken: APP_CONFIG['refreshToken'] }), { "headers" : this.headers } ).subscribe( data => {
let res : any = data;
APP_CONFIG['accessToken'] = res.accessToken;
APP_CONFIG['accessTokenTimestamp'] = new Date().getTime();
resolve(APP_CONFIG['accessToken']);
}, err => {console.log('error'); reject(null); })
});
}
getuserinfos(){
return this.http.get(this.api+ 'getuserinfos', { "headers" : this.headers } ).subscribe( data => {
console.log('result getUserInfos =>', data);
},
( err : HttpErrorResponse ) => {
if ( err.error instanceof Error ) { console.log('An error occurred requete login:', err.error.message); }
else {
console.log('error => ', err)
}
});
当我调用 getUserInfos() 并且 token 已过期时出现以下错误:
error => TypeError:您在需要流的位置提供了“未定义”。您可以提供 Observable、Promise、Array 或 Iterable。
这与此行为有关吗?
More rarely, an interceptor may choose to completely handle the request itself, and compose a new event stream instead of invoking next.handle(). This is acceptable behavior, but keep in mind further interceptors will be skipped entirely. It is also rare but valid for an interceptor to return multiple responses on the event stream for a single request. Source
最佳答案
我终于用不同的实现来管理它。这是我的拦截器:
@Injectable()
export class JwtService implements HttpInterceptor {
constructor(public inj: Injector){}
private fixUrl(url: string) {
if (url.indexOf('http://') >= 0 || url.indexOf('https://') >= 0)
return url;
else
return APP_CONFIG['apiEndPoint'] + url;
}
intercept(req : HttpRequest<any>, next : HttpHandler) : Observable<HttpEvent<any>> {
// Clone request
var headers = {}
if (APP_CONFIG['accessToken']){
headers = { 'Authorization' : APP_CONFIG['accessToken'] };
}
const cloneRequest = req.clone( { setHeaders : headers });
return next.handle(cloneRequest).do(data => {
if (data instanceof HttpResponse) {
// Some logic
}
})
.catch((res)=> {
if (res.status === 401 || res.status === 403) {
if (APP_CONFIG['accessToken'])
{
const auth = this.inj.get(AuthService);
return auth.getUpdatedAccessToken().flatMap( token => {
// Clone the previous request
let clonedRequestRepeat = req.clone({
headers: req.headers.set('Authorization' , APP_CONFIG['accessToken'] ),
url: this.fixUrl(req.url)
});
// Request agin
return next.handle(clonedRequestRepeat).do(event => {
if (event instanceof HttpResponse) {
console.log('Repeat response of server : ', event);
}
});
});
}else { return Observable.throw('Not authenticated'); }
}
else { // Not 401
return Observable.throw(res);
}
})
}
}
AuthService.ts
getUpdatedAccessToken() : Observable<any>{
return this.http.post(this.api+ 'getaccesstoken', JSON.stringify({refreshToken: APP_CONFIG['refreshToken'] }), { "headers" : this.headers } )
.map((response: any) => {
if (response.code == 0){
APP_CONFIG['accessToken'] = response.accessToken;
}
return response
})
}
关于javascript - 在拦截器angular2中实现http请求,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47303974/