How to pass a param to HttpInterceptor?

前端 未结 4 2105
别跟我提以往
别跟我提以往 2020-12-15 04:11

I am using Angular 4.3.1 and HttpClient. There is an HttpInterceptor to set some headers.

In some http get requests I need to set a different header. Is there anywa

相关标签:
4条回答
  • 2020-12-15 04:13

    You can use setParam option of request.

    export class WebReqInterceptor implements HttpInterceptor {
    stringifiedData: any;  
    intercept(request: HttpRequest<any>, next: HttpHandler): Observable<any> {
        if (window.sessionStorage.getItem('token')) {
            this.stringifiedData=JSON.parse(window.sessionStorage.getItem('token'));
            request = request.clone({
                setParams:{
                    access_token:this.stringifiedData.access_token
                }                          
            });
            return next.handle(request);
        }
        else{
            return next.handle(request);
        }
    }
    

    }

    0 讨论(0)
  • 2020-12-15 04:20

    Maybe there's a better way to handle this problem, but as a workaround you can create and pass custom HttpParams to request and then check them in the interceptor. For example:

    export class CustomHttpParams extends HttpParams {
      constructor(public param1: boolean) {
       super();
      }
    }
    

    Using this class in http call:

    this.http.get('https://example.com', {
      params: new CustomHttpParams(true)
    })
    

    And now in interceptor:

    intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
      if (request.params instanceof CustomHttpParams && request.params.param1) 
        request = request.clone({
          setHeaders: {
            'header1': 'xxxxxx'
          }
        });
      else
        request = request.clone({
          setHeaders: {
            'header2': 'yyyyyy'
          }
        });
    
      return next.handle(request);
    }
    
    0 讨论(0)
  • 2020-12-15 04:21

    Currently, Angular does not support passing "interceptor config/metadata" via the HttpRequest object (it has been an open issue for quite some time).

    As a possible workaround, we can define a new MyHttpParams class which extends Angular's HttpParams, adding a new interceptorMetadata property.

    Note that MyHttpParams must override the append, set and delete methods so that they return MyHttpParams instead of Angular's HttpParams. If we don't do this, our interceptorMetadata will be "dropped" when those methods are invoked (e.g. if an interceptor adds some HTTP param, the next interceptors will not get the interceptorMetadata).

    import {HttpParams} from '@angular/common/http';
    
    export interface InterceptorMetadata {
        readonly customParam1: string;
        readonly customParam2: number;
        // etc.
    }
    
    export interface MyHttpParamsConfig {
        interceptorMetadata: Partial<InterceptorMetadata>;
        params: string | Record<string, string | string[]>; // the actual params which will be included in the real request
    }
    
    export class MyHttpParams extends HttpParams {
        public readonly interceptorMetadata: Partial<InterceptorMetadata>;
    
        constructor({params, interceptorMetadata}: Partial<MyHttpParamsConfig> = {}) {
            if(typeof params === 'string') {
                super({fromString: params});
            }
            else if(typeof params === 'object') {
                super({fromObject: params});
            }
            else {
                super();
            }
    
            this.interceptorMetadata = interceptorMetadata;
        }
    
        // orverrides HttpParams.append
        append(param: string, value: string): MyHttpParams {
            const updatedHttpParams = super.append(param, value);
            return new MyHttpParams({
                interceptorMetadata: this.interceptorMetadata,
                params: updatedHttpParams.toString()
            });
        }
    
        // orverrides HttpParams.set
        set(param: string, value: string): MyHttpParams {
            const updatedHttpParams = super.set(param, value);
            return new MyHttpParams({
                interceptorMetadata: this.interceptorMetadata,
                params: updatedHttpParams.toString()
            });
        }
    
        // orverrides HttpParams.delete
        delete(param: string, value?: string): MyHttpParams {
            const updatedHttpParams = super.delete(param, value);
            return new MyHttpParams({
                interceptorMetadata: this.interceptorMetadata,
                params: updatedHttpParams.toString()
            });
        }
    }
    

    Then for example when calling HttpClient.get() we can pass an instance of our extended MyHttpParams:

    const myHttpParams = new MyHttpParams({
        interceptorMetadata: {
            customParam1: 'test', // this will NOT be part of the final request
        },
        params: 'someActualUrlQueryString=someValue' // this will be part of the final request
    });
    
    httpClient.get(myUrl, {params: myHttpParams})
    

    Finally, in our interceptor we can use interceptorMetadata:

    intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
        const {params} = req;
        if(params instanceof MyHttpParams) {
            if (params.interceptorMetadata && params.interceptorMetadata.customParam1 === 'test') { 
                // do something
            }
        }
        // ...
    }
    

    Thanks to JWess for the original answer which this is based on (it was just missing the append, set and delete overrides)

    0 讨论(0)
  • 2020-12-15 04:26

    I wrote an interceptor for handling Http error responses. I wanted to allow specific Http calls to instruct the interceptor to ignore certain response status codes, while also retaining the ability to pass params to the Http call. Here is the solution I ended up with. (Thanks, Aleksey for the initial idea in your answer).

    Extend HttpParams:

    import { HttpParams } from '@angular/common/http';
    import { HttpParamsOptions } from '@angular/common/http/src/params';
    
    // Cause the HttpErrorInterceptor to ignore certain error response status codes like this:
    //
    //  this.http.get<TypeHere>(`URL_HERE`, {
    //    params: new InterceptorHttpParams({ statusCodesToIgnore: [400, 401] }, {
    //      complete: 'false',
    //      offset: '0',
    //      limit: '50'
    //    })
    //  })
    
    export class InterceptorHttpParams extends HttpParams {
      constructor(
        public interceptorConfig: { statusCodesToIgnore: number[] },
        params?: { [param: string]: string | string[] }
      ) {
        super({ fromObject: params } as HttpParamsOptions);
      }
    }
    

    Interceptor:

    intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
      return next.handle(req).pipe(
        tap(
          () => {},
          (error: any) => {
            if (error instanceof HttpErrorResponse) {
              const regEx = /^[4-5][0-9][0-9]$/; // 4XX and 5XX status codes
    
              if (regEx.test(error.status.toString())) {
                  const errorMessage = this.getErrorMessageFromStatus(error.status);
    
                  if (!this._shouldIgnoreError(req, error)) {
                    console.log(`ERROR INTERCEPTOR: ${error.status}`);
                    this.toastService.alert(errorMessage);
                  }
              }
            }
          })
      );
    }
    
    // Based on `request.params.interceptorConfig.statusCodesToIgnore`, we can see if we should ignore this error.
    _shouldIgnoreError(request: HttpRequest<any>, errorResponse: HttpErrorResponse) {
      if (request.params instanceof InterceptorHttpParams
        && Array.isArray(request.params.interceptorConfig.statusCodesToIgnore)
        && request.params.interceptorConfig.statusCodesToIgnore.includes(errorResponse.status)) {
    
        return true;
      }
    
      return false;
    }
    
    0 讨论(0)
提交回复
热议问题