javascript - 在拦截器angular2中实现http请求

标签 javascript angular http typescript

我正在尝试处理来自 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/

相关文章:

javascript - 使用 jquery 拆分数组?

php - 如果 IE 则包含文件 [A] 否则包含文件 [B]

angular - GET http://localhost:9000/content/radios/radio.wav 404(未找到)

javascript - angular 中 .next() 函数的解释

javascript - 如何在 JavaScript 的回调中调用 typescript 函数

asp.net - HTTP 响应行为

javascript - 无法在 node.js 控制台上打印 puppeteer 响应

javascript - 我如何在 angularJs 应用程序中从服务器生成并下载 zip 文件?

security - Fiddler 是否为每台机器创建唯一的私有(private)根证书?

http - 使用 Http 代理与 https 代理的优缺点?