如何将参数传递给HttpInterceptor?

时间:2017-09-06 12:44:16

标签: angular typescript interceptor

我使用的是Angular 4.3.1和HttpClient。有一个HttpInterceptor来设置一些标题。

在某些http get请求中,我需要设置不同的标头。无论如何我可以为这个特定的HttpRequest传递一些param给这个HttpInterceptor吗?

@Injectable()
export class MyHttpInterceptor implements HttpInterceptor {

  intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    if(request.custom.param1) // how can i do this 
      request = request.clone({
        setHeaders: {
          'header1': 'xxxxxx'
          }
      });

    else
      request = request.clone({
        setHeaders: {
          'header2': 'yyyyyy'
          }
      });


    return next.handle(request);
  }
}

5 个答案:

答案 0 :(得分:11)

我写了一个用于处理Http错误响应的拦截器。我想允许特定的Http调用来指示拦截器忽略某些响应状态代码,同时还保留将params传递给Http调用的能力。这是我最终得到的解决方案。 (谢谢,Aleksey在你的回答中提出了最初的想法)。

扩展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);
  }
}

拦截器:

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;
}

答案 1 :(得分:10)

也许有更好的方法来处理这个问题,但作为一种解决方法,您可以创建并传递自定义HttpParams来请求,然后在拦截器中检查它们。例如:

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

在http调用中使用此类:

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

现在在拦截器中:

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);
}

答案 2 :(得分:1)

当前,Angular不支持通过HttpRequest对象传递“拦截器配置/元数据”(在相当长一段时间内它一直是open issue)。

作为一种可能的解决方法,我们可以定义一个新的MyHttpParams类,该类扩展了Angular的HttpParams,并添加了一个新的interceptorMetadata属性。

请注意,MyHttpParams必须覆盖appendsetdelete方法,以便它们返回MyHttpParams而不是Angular的HttpParams。如果我们不这样做,则调用这些方法时,interceptorMetadata将被“丢弃”(例如,如果拦截器添加了一些HTTP参数,则下一个拦截器将不会获得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()
        });
    }
}

然后例如,当调用HttpClient.get()时,我们可以传递扩展的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})

最后,在拦截器中,我们可以使用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
        }
    }
    // ...
}

感谢JWess为其提供的原始答案(它只是缺少appendsetdelete覆盖)

答案 3 :(得分:0)

您可以使用request的setParam选项。

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);
    }
}

}

答案 4 :(得分:0)

对于偶然发现相同问题的任何人,我们可以在 Angular 的新版本中在 HttpParams 中传递自定义参数。但是我们必须记住 HttpParams 是一个不可变对象。对于不可变对象,每次调用 params.append() 都会返回一个新对象。因此,我们必须将返回的新对象重新分配回 params,如下所示,

 var params = new HttpParams();
 // Notice that I am re-assigning the params object
 params = params.append('showErrorMessage', 'false'); 
 return this.http.get(url, { params: params });

在拦截器中,我们可以这样访问值

req.params.get('showErrorMessage')