How to handle unauthorized requests(status with 401 or 403) with new httpClient in angular 4.3
You should use your interceptor and just handle it like this:
@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 of(err.message); // or EMPTY may be appropriate here } return throwError(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).pipe(catchError(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 }}
no need for the http service wrapper.
to use the router you'll need a factory provider like:
providers: [ { provide: HTTP_INTERCEPTORS, useFactory: function(router: Router) { return new AuthInterceptor(router); }, multi: true, deps: [Router] }, .... other providers ... ]
where ever you're providing the interceptor (probably app.module). don't use an arrow function. they aren't supported in factory functions when you try to build for prod.
Working plunk: https://plnkr.co/edit/UxOEqhEHX1tCDVPDy488?p=preview
From the @bryan60 suggestion I made few changes to his solution
In app.module.ts:
providers: [ { provide: HTTP_INTERCEPTORS, useFactory: function(injector: Injector) { return new AuthInterceptor(injector); }, multi: true, deps: [Injector] }, .... other providers ...]
and in 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)); }}
If you are using AOT in building try:
export function authInterceptorFactory(injector: Injector) { return new AuthInterceptor(injector);}providers: [ { provide: HTTP_INTERCEPTORS, useFactory: authInterceptorFactory, multi: true, deps: [Injector] }, .... other providers ...]
the above @bryan60 answer is works fine , if any one facing issue like me with catch the error in below line
return next.handle(authReq).catch(x=> this.handleAuthError(x));
using do() handle the error(if you face issue with catch())
import in file:
import 'rxjs/add/operator/do';
handle error:
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'; }}
I hope this is help someone.