Как обрабатывать несанкционированные запросы (статус с 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 ...
]
где бы вы ни предоставляли перехватчик (возможно, приложение.модуль.) не используйте функцию стрелки. они не поддерживаются в заводских функциях при попытке построить для prod.
рабочая бухнуть: https://plnkr.co/edit/UxOEqhEHX1tCDVPDy488?p=preview
из предложения @bryan60 я внес несколько изменений в его решение
в приложение.модуль.ТС:
providers: [
{
provide: HTTP_INTERCEPTORS,
useFactory: function(injector: Injector) {
return new AuthInterceptor(injector);
},
multi: true,
deps: [Injector]
},
.... other providers ...
]
и в auth-перехватчике.услуга.ТС:
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';
}
}
Я надеюсь, это поможет кому-то.