本文介绍了角 5.2 &RxJS 5.5 HttpInterceptor retryWhen,但更新请求?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试拦截 401 响应,在再次尝试请求之前发送刷新令牌请求(但具有不同的标头).除了 retryWhen 没有让我修改原始请求标头外,我让它工作.所以我一直在尝试使用 catchError 代替,但我似乎无法再次执行请求.

I am trying to intercept a 401 response, send a refresh token request before trying request again (but with a different header). I have it working except retryWhen does not give me to modify the original request header. So I've been trying to use catchError instead but I cannot seem to execute the request again.

这是我当前的retryWhen:

import {Injectable} from '@angular/core';
import {
    HttpInterceptor, HttpHandler, HttpRequest, HttpEvent, HttpErrorResponse
}
    from '@angular/common/http';

import {Observable} from 'rxjs/Observable';
import {CustomerService} from "../customer/customer.service";
import * as ApplicationSettings from "application-settings";
import {retryWhen, map} from "rxjs/operators";
import {LoginResponse} from "./LoginResponse";

/**
 * This takes a request that requires an access_token and refreshes it on 401 errors.
 */
@Injectable()
export class RefreshTokenInterceptor implements HttpInterceptor {

    public constructor(private customer: CustomerService) {}

    intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
        return next.handle(req).pipe(
            retryWhen(errors => {
                return Observable.create(observer => {
                    errors.forEach((error: HttpErrorResponse) => {
                        if (error.status === 401) {
                            let refresh_token = ApplicationSettings.getString('refresh_token');

                            return this.customer.refreshToken(refresh_token).subscribe(
                                (response: LoginResponse) => {
                                    this.customer.setToken(response);

                                    let headers = req.headers.set('Authorization', `Bearer ${response.access_token}`);
                                    console.log(`Bearer ${response.access_token}`);
                                    let newReq = req.clone({headers: headers});
                                    observer.next(next.handle(newReq));
                                    observer.complete();
                                },
                                error2 => {
                                    observer.error();
                                }
                            );
                        } else {
                            observer.error();
                        }
                    });
                });
            })
        );
    }
}

如果我用 catchError 替换 retryWhen:

        catchError((err, caught) => {
            console.log('err: ' + JSON.stringify(err));

            if (err.status === 401) {
                console.log('401 !!!! REFRESH MEH!');
                let newReqOb: Observable<HttpEvent<any>> = Observable.create(observer => {
                    console.log('going to refresh token');
                    let refresh_token = ApplicationSettings.getString('refresh_token');

                    let refresh = this.customer.refreshToken(refresh_token);

                    refresh.subscribe((response: LoginResponse) => {
                        console.log('token refreshed!');
                        this.customer.setToken(response);


                        let access_token = ApplicationSettings.getString('access_token');
                        let headers = req.headers.set('Authorization', `Bearer ${access_token}`);

                        console.log(`Bearer ${access_token}`);

                        let newReq = req.clone({headers: headers});

                        observer.next(next.handle(newReq)); // <-- HERE IT WONT FIRE
                        observer.complete();

                    });

                });

                return newReqOb;
            }

            return caught;
        })

重要的部分是我正在返回 next.handle(newReq) 并且它似乎没有触发请求.如果我将它切换到 next.handle(newReq).subscribe(),请求将被触发但不会触发回调.

The important part is I am returning next.handle(newReq) and it doesn't seem to fire the request. If I switch it to next.handle(newReq).subscribe(), the request will fire but no callbacks are triggered.

这是带有 retryWhen 的完整示例:

Here is the full example with retryWhen:

import {Inject, Injectable} from '@angular/core';
import {
    HttpInterceptor, HttpHandler, HttpRequest, HttpEvent, HttpErrorResponse, HttpClient
}
    from '@angular/common/http';

import {Observable, ObservableInput} from 'rxjs/Observable';
import {CustomerService} from "../customer/customer.service";
import * as ApplicationSettings from "application-settings";
import {retryWhen, map, catchError} from "rxjs/operators";
import {LoginResponse} from "./LoginResponse";
import {APP_CONFIG, AppConfig} from "../../app.config";

/**
 * This takes a request that requires an access_token and refreshes it on 401 errors.
 */
@Injectable()
export class RefreshTokenInterceptor implements HttpInterceptor {

    public constructor(private customer: CustomerService, private http: HttpClient, @Inject(APP_CONFIG) private config: AppConfig) {}

    intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
        return next.handle(req).pipe(
            catchError((err, caught) => {
                console.log('err: ' + JSON.stringify(err));

                if (err.status === 401) {
                    console.log('401 !!!! REFRESH MEH!');
                    let newReqOb: Observable<HttpEvent<any>> = Observable.create(observer => {
                        console.log('going to refresh token');
                        let refresh_token = ApplicationSettings.getString('refresh_token');

                        let refresh = this.customer.refreshToken(refresh_token);

                        refresh.subscribe((response: LoginResponse) => {
                            console.log('token refreshed!');
                            this.customer.setToken(response);


                            let access_token = ApplicationSettings.getString('access_token');
                            let headers = req.headers.set('Authorization', `Bearer ${access_token}`);

                            console.log(`Bearer ${access_token}`);

                            let newReq = req.clone({headers: headers});

                            observer.next(next.handle(newReq));
                            observer.complete();

                        });

                    });

                    return newReqOb;
                }

                return caught;
            })
        );
    }
}

推荐答案

我确实发现了问题,这是结果代码:

I did find out the issue, here is the resulting code:

import {Inject, Injectable} from '@angular/core';
import {
    HttpInterceptor, HttpHandler, HttpRequest, HttpEvent, HttpErrorResponse, HttpClient
}
    from '@angular/common/http';

import {Observable, ObservableInput} from 'rxjs/Observable';
import {CustomerService} from "../customer/customer.service";
import * as ApplicationSettings from "application-settings";
import {catchError, switchMap, finalize} from "rxjs/operators";
import {LoginResponse} from "./LoginResponse";
import {APP_CONFIG, AppConfig} from "../../app.config";
import {RouterExtensions} from "nativescript-angular/router";

/**
 * This takes a request that requires an access_token and refreshes it on 401 errors.
 * @TODO What happens on 400 errors?
 */
@Injectable()
export class RefreshTokenInterceptor implements HttpInterceptor {

    isRefreshingToken: boolean = false;

    public constructor(private customer: CustomerService,
                       private http: HttpClient,
                       private router: RouterExtensions,
                       @Inject(APP_CONFIG) private config: AppConfig) {}

    intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
        let validate = {
            is_api_v1: req.url.indexOf('api/v1') > -1,
            is_not_register_end_point: !(req.url.indexOf('api/v1/customers') > -1 && req.method === 'POST')
        };

        if (validate.is_api_v1 && validate.is_not_register_end_point) {
            return next.handle(req).pipe(
                catchError((err, caught) => {
                    if (err instanceof HttpErrorResponse && err.status === 401) {
                        console.log(req.url);
                        console.log('Injecting Refresh Token');

                        return this.handle401Error(req, next);
                    }

                    // return caught;
                })
            );
        } else {
            return next.handle(req);
        }

    }

    handle401Error(req: HttpRequest<any>, next: HttpHandler) {
        //-- Test if we are refreshing so we are not stuck in an infinite loop
        if (!this.isRefreshingToken) {
            this.isRefreshingToken = true;

            let refresh_token = ApplicationSettings.getString('refresh_token');
            let refresh = this.customer.refreshToken(refresh_token);

            return refresh.pipe(
                switchMap((tokenResp: LoginResponse) => {
                    this.customer.setToken(tokenResp);

                    let access_token = ApplicationSettings.getString('access_token');
                    let headers = req.headers.set('Authorization', `Bearer ${access_token}`);

                    return next.handle(req.clone({headers: headers}));
                }),
                catchError(error => {
                    ApplicationSettings.setBoolean("authenticated", false);
                    this.router.navigate(["/login"], { clearHistory: true, queryParams: {
                        error: 'Your session is no longer valid, please log in again',
                    }});

                    return Observable.throw("");
                }),
                finalize(() => {
                    this.isRefreshingToken = false;
                })
            )
        }
    }
}

这篇关于角 5.2 &amp;RxJS 5.5 HttpInterceptor retryWhen,但更新请求?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

09-25 12:50