typescript 如何将参数传递给HttpInterceptor?

rnmwe5a2  于 2023-01-14  发布在  TypeScript
关注(0)|答案(7)|浏览(149)

我用的是Angular 4.3.1和HttpClient,有一个HttpInterceptor来设置一些头。
在一些http get请求中我需要设置一个不同的头。有没有什么方法可以为那个特定的HttpRequest传递一些参数给这个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);
  }
}
bprjcwpo

bprjcwpo1#

我编写了一个拦截器来处理Http错误响应。我希望允许特定的Http调用来指示拦截器忽略某些响应状态代码,同时还保留向Http调用传递参数的能力。以下是我最终得到的解决方案。(谢谢Aleksey在回答中提出的最初想法)。
扩展HttpParams:

import { HttpParams, HttpParamsOptions  } from '@angular/common/http';

// 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: (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;
}
fkaflof6

fkaflof62#

也许有更好的方法来处理这个问题,但是作为一种解决方案,您可以创建自定义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);
}
2eafrhcq

2eafrhcq3#

在“Angular 12+”中,有一个新属性HttpRequest.context用于解决此问题。
拦截器可以使用的共享和可变上下文https://angular.io/api/common/http/HttpRequest#context

k2arahey

k2arahey4#

目前,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覆盖)

kuhbmx9i

kuhbmx9i5#

您可以使用请求的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);
    }
}

}

kfgdxczn

kfgdxczn6#

对于遇到同样问题的人,我们可以在新版本的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')
ngynwnxp

ngynwnxp7#

正如@btx所说,自Angular 12 +以来,有一个新属性HttpRequest.context,可用于在HttpClientHttpInterceptor之间共享数据。
下面是一个示例代码,用于为每个安全请求添加Authorization报头。

export const IS_ROUTE_SECURED = new HttpContextToken<boolean>(() => false);

export class CacheInterceptor implements HttpInterceptor {
  constructor(private authService: AuthService) {}

  intercept(request: HttpRequest<unknown>, next: HttpHandler): Observable<HttpEvent<unknown>> {
    const headers = {
      ['Access-Control-Allow-Origin']: CONSTANTS.API_BASE_URL
    } as Record<string, string>;

    if(request.context.get(IS_ROUTE_SECURED)) {
      headers['Authorization'] = 'Bearer ' + this.authService.getAuthToken();
    }

    return next.handle(request.clone({ setHeaders: headers }));
  }
}

// inside a service
this.httpClient.get('/api/users', {
  context: new HttpContext().set(IS_ROUTE_SECURED, true)
}).subscribe(...);

相关问题