Search code examples
angularangular-http-interceptors

Why does this interceptor only trigger on the Sent-Event, but not the actual response?


I'm receiving some multipart/mixed content from a server that contains some JSON as well as bytes and need to parse it into an object in Angular.

This is how I send out my request:

public sendRequest(headerData: string): Observable<MultipartResponse> {

    let requestHeaders: HttpHeaders = new HttpHeaders();
    requestHeaders = requestHeaders.set("X-Header-Data", headerData);
    
    return httpClient.get("localhost:12345/myroute", { headers: requestHeaders}) as Observable<MultipartResponse>;
}

I have implemented a HttpInterceptor to parse the response like this:

@Injectable({ providedIn: 'root' })
export class MyInterceptor implements HttpInterceptor {

    public intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {

        return next.handle(request).pipe(map((event: HttpEvent<any>) => {

            if (event instanceof HttpResponse)
                return response.clone({ body: new MultipartResponse(event.body); });

            return event;
        }));
    }
}

and registered it like this in main.ts:

bootstrapApplication(AppComponent, {
  providers: [
    importProvidersFrom(HttpClientModule),
    provideHttpClient(withInterceptorsFromDi()),
    {
      provide: HTTP_INTERCEPTORS,
      useClass: MyInterceptor,
      multi: true
    }
  ],
}).catch((err) => console.error(err));

Now, when I send out my request, the interceptor triggers once on the Sent-Event that confirms the request was successfully send, but then never again. Instead, the response goes directly into the caller, which then throws an error because it tries to parse the entire body as JSON.


Solution

  • Because it errors out: as response type is not set, so it uses default JSON parser (response type must be set beforehand), and then it errors out when tries to parse the response, never reaching your interceptor method (the interceptor can catch it with catchError((error: HttpErrorResponse) => {...).

    So, you need to disable the default parser. You could add some flag to check if the request has your multipart header data, and then disable JSON parser by changing response type to text, and then parse the response with your custom parser (customize as needed):

    public intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    
        const isMixedReq = request.headers.get('X-Header-Data');
    
        if (isMixedReq && request.responseType === 'json') {
    
          request = request.clone({responseType: 'text'});
    
          return next.handle(request).pipe(map((response: HttpEvent<any>) => {
    
            if (response instanceof HttpResponse && typeof response.body === 'string')
                return response.clone({ body: new MultipartResponse(response.body) });
    
            return response;
          }));
      } else {
        return next.handle(request);
      }
    }
    

    approach source: Custom JSON parsing