【问题标题】:Implement http request in interceptor angular2在拦截器angular2中实现http请求
【发布时间】:2023-03-19 00:19:01
【问题描述】:

我正在尝试使用 httpClientModule 处理来自 interceptor 的 401 响应。身份验证基于 JWT,带有 accessToken 和 refreshToken。如果accessToken过期了,我需要用refreshToken请求api获取一个新的。我想在应该生成新令牌时阻止请求,获取一个新令牌,然后附加新的 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() 并且令牌已过期时,我收到以下错误:

error => TypeError:您在预期流的位置提供了“未定义”。您可以提供 Observable、Promise、Array 或 Iterable。

这是否与此行为有关?

更罕见的是,拦截器可能会选择完全处理请求本身,并组成一个新的事件流,而不是调用 next.handle()。这是可以接受的行为,但请记住,进一步的拦截器将被完全跳过。拦截器在单个请求的事件流上返回多个响应也是罕见但有效的。 Source

【问题讨论】:

  • 你是如何调用 getUserInfos() 的?
  • 这是来自我的组件的简单调用:this.authService.getuserinfos()(我猜前后的逻辑不相关,所以我没有将其添加到问题中)
  • this.authService.getuserinfos().subscribe() 还是 this.authService.getuserinfos().then() ?
  • 问题不在这里没关系。我可以从 getUserInfos 生成 Promise 或 Observable 并从请求中解析/拒绝答案,这与 getuserinfos() 中的 console.log() 相同

标签: javascript angular http typescript


【解决方案1】:

我终于用不同的实现来管理它。这是我的拦截器:

@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
        })
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-02-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-02-28
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多