Как обрабатывать неавторизованные запросы (статус с 401 или 403) с новым httpClient в angular 4.3

У меня есть auth-interceptor.service.ts обрабатывать запросы

import {Injectable} from '@angular/core';
import {HttpErrorResponse, HttpEvent, HttpHandler, HttpInterceptor, HttpRequest} from '@angular/common/http';
import {Observable} from 'rxjs/Observable';
import {Cookie} from './cookie.service';
import {Router} from '@angular/router';

@Injectable()
export class AuthInterceptor implements HttpInterceptor {
    constructor(private router: Router) {}
    intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
        // Clone the request to add the new header.
        const authReq = req.clone({headers: req.headers.set(Cookie.tokenKey, Cookie.getToken())});
        // Pass on the cloned request instead of the original request.
        return next.handle(authReq).catch(this.handleError);
    }

    private handleError(err: HttpErrorResponse): Observable<any> {
        console.log(err);
        if (err.status === 401 || err.status === 403) {
            Cookie.deleteUser();
            this.router.navigateByUrl(`/login`);
            return Observable.of(err.message);
        }
        // handle your auth error or rethrow
        return Observable.throw(err);
    }
}

Но я получаю следующую ошибку. На самом деле ничего не происходит, так как он не удаляет cookie или не переходит на страницу входа. Будем благодарны за любую помощь или предложения.

введите описание изображения здесь

3 ответа

Решение

Вы должны использовать свой перехватчик и просто обрабатывать его так:

@Injectable()
export class AuthInterceptor implements HttpInterceptor {
    constructor(private router: Router) { }

    private handleAuthError(err: HttpErrorResponse): Observable<any> {
        //handle your auth error or rethrow
        if (err.status === 401 || err.status === 403) {
            //navigate /delete cookies or whatever
            this.router.navigateByUrl(`/login`);
            // if you've caught / handled the error, you don't want to rethrow it unless you also want downstream consumers to have to handle it as well.
            return Observable.of(err.message);
        }
        return Observable.throw(err);
    }

    intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    // Clone the request to add the new header.
        const authReq = req.clone({headers: req.headers.set(Cookie.tokenKey, Cookie.getToken())});
        // catch the error, make specific functions for catching specific errors and you can chain through them with more catch operators
        return next.handle(authReq).catch(x=> this.handleAuthError(x)); //here use an arrow function, otherwise you may get "Cannot read property 'navigate' of undefined" on angular 4.4.2/net core 2/webpack 2.70
    }
}

нет необходимости в обертке службы http.

чтобы использовать роутер, вам понадобится такой провайдер, как:

 providers: [
     {
         provide: HTTP_INTERCEPTORS,
         useFactory: function(router: Router) {
           return new AuthInterceptor(router);
         },
         multi: true,
         deps: [Router]
      },
      .... other providers ...
  ]

где бы вы ни предоставляли перехватчик (вероятно, app.module). не используйте функцию стрелки. они не поддерживаются в заводских функциях, когда вы пытаетесь собрать для prod.

Рабочий план: https://plnkr.co/edit/UxOEqhEHX1tCDVPDy488?p=preview

Из предложения @bryan60 я внес несколько изменений в его решение

В app.module.ts:

providers: [
     {
        provide: HTTP_INTERCEPTORS,
        useFactory: function(injector: Injector) {
            return new AuthInterceptor(injector);
        },
        multi: true,
        deps: [Injector]
    },
      .... other providers ...
]

и в auth-interceptor.service.ts:

import {Injectable, Injector} from '@angular/core';
import {HttpErrorResponse, HttpEvent, HttpHandler, HttpInterceptor, HttpRequest} from '@angular/common/http';
import {Observable} from 'rxjs/Observable';
import {Cookie} from './cookie.service';
import {Router} from '@angular/router';
import {UserService} from './user.service';
import {ToasterService} from '../toaster/toaster.service';
import 'rxjs/add/operator/catch';
import 'rxjs/add/observable/throw';

@Injectable()
export class AuthInterceptor implements HttpInterceptor {
    constructor(private injector: Injector) {}

    private handleError(err: HttpErrorResponse): Observable<any> {
        let errorMsg;
        if (err.error instanceof Error) {
            // A client-side or network error occurred. Handle it accordingly.
            errorMsg = `An error occurred: ${err.error.message}`;
        } else {
            // The backend returned an unsuccessful response code.
            // The response body may contain clues as to what went wrong,
            errorMsg = `Backend returned code ${err.status}, body was: ${err.error}`;
        }
        if (err.status === 404 || err.status === 403) {
            this.injector.get(UserService).purgeAuth();
            this.injector.get(ToasterService).showError(`Unauthorized`, errorMsg);
            this.injector.get(Router).navigateByUrl(`/login`);
        }
        console.error(errorMsg);
        return Observable.throw(errorMsg);
    }

    intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
        // Clone the request to add the new header.
        const authReq = req.clone({headers: req.headers.set(Cookie.tokenKey, Cookie.getToken())});
        // Pass on the cloned request instead of the original request.
        return next.handle(authReq).catch(err => this.handleError(err));
    }
}

Если вы используете AOT в сборке, попробуйте:

export function authInterceptorFactory(injector: Injector) {
    return new AuthInterceptor(injector);
}

providers: [
         {
            provide: HTTP_INTERCEPTORS,
            useFactory: authInterceptorFactory,
            multi: true,
            deps: [Injector]
        },
          .... other providers ...
]

Приведенный выше ответ @bryan60 работает нормально, если кто-то сталкивается с проблемой, подобной мне, с ошибкой в ​​строке ниже

return next.handle(authReq).catch(x=> this.handleAuthError(x));

использование do() обрабатывает ошибку (если вы столкнулись с проблемой catch())

импортировать в файл:

import 'rxjs/add/operator/do';

обработать ошибку:

return next.handle(authReq)
 .do(
    success => {/*todo*/},
    err => {this.handleAuthError(authReq)}
    );
}

handleAuthError(err: any) {
    if(err.status === 401 || err.status === 403) {
    this.storageService.clear();
    window.location.href = '/home';
    }
}

Я надеюсь, что это поможет кому-то.

Другие вопросы по тегам