integrate the interceptor in angular 9?

How to integrate the interceptor in angular 9?

What is Interceptor in angular?

Interceptors provide a mechanism to intercept and/or mutate outgoing requests or incoming responses. They are very similar to the concept of middle-ware with a framework like Express, except for the front-end.

Why do we use interceptors?

Interceptors?can be really useful for features like?caching and logging. Interceptors are a way to do some work for?every single HTTP request or response.

  • Add a token?or some custom HTTP header for all outgoing HTTP requests
  • Catch HTTP responses?to do some custom formatting (i.e. convert CSV to JSON) before handing the data over to your service/component
  • Log all HTTP activity?in the console
  • Handle HTTP request by its status code and do common?error handle?here to manage all HTTP errors.

How we configure interceptor? OR?Basic Setup of interceptor.

To implement an interceptor, you’ll want to create a class that’s?injectable?and that implements?HttpInterceptor. The intercept method takes two arguments,?req and next, and returns an?observable of type HttpEvent.

  • req?is the request object itself and is of type HTTP Request.
  • next?is the HTTP handler, of type HTTP Handler. The handler has a handle method that returns our desired HttpEvent observable.

First, create a service that implements HttpInterceptor:

import { HttpInterceptor} from '@angular/common/http';
import { Injectable } from '@angular/core';
 
@Injectable()
export class TokenInterceptorService implements HttpInterceptor {
   intercept(req: HttpRequest<any>, next: HttpHandler):   Observable<HttpEvent<any>> {
       // All HTTP requests are going to go through this method
   }
}        

It has to be added to the list of all?HTTP_INTERCEPTORS, which can be done that way in?app.module.ts:

@NgModule({
  ...
  providers: [{
    provide: HTTP_INTERCEPTORS, 
    useClass: TokenInterceptorService, 
    multi: true
  }]
})
export class AppModule { }        

How we can use multiple interceptors?

You could define?multiple interceptors?with something like this

providers: [
  { provide: HTTP_INTERCEPTORS, useClass: MyInterceptor, multi: true },
  { provide: HTTP_INTERCEPTORS, useClass: MySecondInterceptor, multi: true }],        

The interceptors will be?called in the order?in which they were provided. So with the above,?MyInterceptor would handle HTTP requests first.

How to?Modifying Requests?using Interceptor?

HTTP Request?objects are immutable, so in order to modify them, we need to first make a copy, then modify the copy and call handle on the modified copy. The request object’s clone method comes-in handy to do just that.

Here’s a simple interceptor that sets the filter query param to a value of completed

@Injectable()
export class MyInterceptor implements HttpInterceptor {
  intercept( req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    if (req.body) {
      const duplicate = req.clone({ body: req.body.replace(/pizza/gi, '??') });
      return next.handle(duplicate);
    }
    return next.handle(req);
  }
}        

Here is some example of where we can use interceptor

  1. Looking for Unauthorised Responses
  2. When tokens expire we will generally get a?401 Unauthorised?response back from the server.

  • This gives us an indication that we need the user to log in again to get a new token.
  • We have some choices to make at this point.
  • Do we want to redirect to a specific route that has a login form?
  • Do we want to show a modal?
  • Do we want to attempt to refresh the token?

We need to set up the interceptor to handle responses. The intercept method returns an?observable?which means we can capture the?success and error?channels for a response and operate on them however we like

This is also a great spot to cache any failed requests.

// jwt.interceptor.ts
 
@Injectable()
export class JwtInterceptor implements HttpInterceptor {
  constructor(public auth: AuthService) {}
  intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    
    return next.handle(request).do((event: HttpEvent<any>) => {
      if (event instanceof HttpResponse) {
        // do stuff with response if you want
      }
    }, (err: any) => {
      if (err instanceof HttpErrorResponse) {
        if (err.status === 401) {
          // redirect to the login route
          // or show a modal
        }
      }
    });
  }
}
// auth.service.ts
 
import { HttpRequest } from '@angular/common/http';
 
@Injectable()
export class AuthService {
cachedRequests: Array<HttpRequest<any>> = [];
public collectFailedRequest(request): void {
    this.cachedRequests.push(request);
  }
public retryFailedRequests(): void {
    // retry the requests. this method can
    // be called after the token is refreshed
  }
}        

2. Manage Authentication

First on the list is authentication! It is just so fundamental for many applications that we have a proper authentication system in place.?This is one of the most common use cases for interceptors?and for a good reason. It fits right in!

There are several things connected to authentication we can do:

  • Add bearer token
  • Refresh Token
  • Redirect to the login page

We should also have some?filtering?for when we send the?bearer token. If we don’t have a token yet, then we are probably logging in and should not add the token. And if we are doing calls to other domains, then we would also not want to?add the token. For example,?if we send errors into Slack.

This is also a bit more complex than the other interceptors.

Here is an example of how it can look with some explaining comments

import { Injectable } from "@angular/core";
import { HttpEvent, HttpInterceptor, HttpHandler,HttpRequest, HttpErrorResponse } from "@angular/common/http";
import { throwError, Observable, BehaviorSubject, of } from "rxjs";
import { catchError, filter, take, switchMap } from "rxjs/operators";
 
@Injectable()
export class AuthInterceptor implements HttpInterceptor {
  private AUTH_HEADER = "Authorization";
  private token = "secrettoken";
  private refreshTokenInProgress = false;
  private refreshTokenSubject: BehaviorSubject<any> = new BehaviorSubject<any>(null);
 
  intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
 
    if (!req.headers.has('Content-Type')) {
      req = req.clone({
        headers: req.headers.set('Content-Type', 'application/json')
      });
    }
 
    req = this.addAuthenticationToken(req);
 
    return next.handle(req).pipe(
      catchError((error: HttpErrorResponse) => {
        if (error && error.status === 401) {
         // 401 errors are most likely going to be because we have an expired token that we need to refresh.
          if (this.refreshTokenInProgress) {
            // If refreshTokenInProgress is true, we will wait until refreshTokenSubject has a non-null value
            // which means the new token is ready and we can retry the request again
            return this.refreshTokenSubject.pipe(
              filter(result => result !== null),
              take(1),
              switchMap(() => next.handle(this.addAuthenticationToken(req)))
            );
          } else {
            this.refreshTokenInProgress = true;
 
            // Set the refreshTokenSubject to null so that subsequent API calls will wait until the new token has been retrieved
            this.refreshTokenSubject.next(null);
            
            return this.refreshAccessToken().pipe(
              switchMap((success: boolean) => {               
                this.refreshTokenSubject.next(success);
                return next.handle(this.addAuthenticationToken(req));
              }),
              // When the call to refreshToken completes we reset the refreshTokenInProgress to false
              // for the next time the token needs to be refreshed
              finalize(() => this.refreshTokenInProgress = false)
            );
          }
        } else {
          return throwError(error);
        }
      })
    );
  }
 
  private refreshAccessToken(): Observable<any> {
    return of("secret token");
  }
 
  private addAuthenticationToken(request: HttpRequest<any>): HttpRequest<any> {
    // If we do not have a token yet then we should not set the header.
    // Here we could first retrieve the token from where we store it.
    if (!this.token) {
      return request;
    }
    // If you are calling an outside domain then do not add the token.
    if (!request.url.match(/www.mydomain.com\//)) {
 return request;
    }
    return request.clone({
      headers: request.headers.set(this.AUTH_HEADER, "Bearer " + this.token)
    });
  }
}        

3. Set Headers

We can do a lot by?manipulating headers. Some things are:

  • Authentication/authorization
  • Caching behaviour; for example, If-Modified-Since
  • XSRF protection

const modified = req.clone({ 
  setHeaders: { "X-Man": "Wolverine" } 
});
return next.handle(modified);        

4. Converting response

When the API returns a format we do not agree with, we can use an interceptor to format it the way we like it.

This could be converting from XML to JSON or like in this example property names from?PascalCase?to?camelCase.

If the back-end doesn’t care about?JSON/JS conventions?we can use an interceptor to rename all the property names to?camelCase.

return next.handle(req).pipe(
  map((event: HttpEvent<any>) => {
    if (event instanceof HttpResponse) {
      let camelCaseObject = mapKeys(event.body, (v, k) => camelCase(k));
      const modEvent = event.clone({ body: camelCaseObject });
      
      return modEvent;
    }
  })
);        


要查看或添加评论,请登录

Gautam Kumar的更多文章

  • ???? ?? ??? ????? ????? ?? ??????

    ???? ?? ??? ????? ????? ?? ??????

    ???? ?? ??? ????? ????? ?? ?????? ???? ??? ???? ???? ?? ??? ???? ?????? ???????? ?? ????? ???? ??? ???? ????? ?? ?????…

    2 条评论
  • What Is LISS Cardio? A Detailed Beginner’s Guide

    What Is LISS Cardio? A Detailed Beginner’s Guide

    What Makes a Workout LISS? One big difference between LISS and other workouts is the intensity of the workouts. Heart…

  • How To Unlock The Power To Change Your Thoughts

    How To Unlock The Power To Change Your Thoughts

    The entrepreneurs I work with tend to have a few things in common: they are smart, ambitious, and highly motivated…

    2 条评论
  • Security Checklist for API Development.

    Security Checklist for API Development.

    Authentication Authentication ensures that your users are who they say they are. Hackers that exploit authentication…

    2 条评论
  • How Generics Work and Why They Are Important

    How Generics Work and Why They Are Important

    How Generics Work and Why They Are Important In Depth understanding of generics in Java SE 8. There has been a lot of…

社区洞察

其他会员也浏览了