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