I am calling an http request using httpClient and using response Type as \'blob\' but the problem is when it goes in error block the response type remains \'blob\'.This is c
I was facing the same issue. In order to handle error response from a blob request you have to parse your error content via FileReader
This is a known Angular Issue and further details can be read there. You can find different solutions for your problem there as well.
For Example you can use this function to parse your error in JSON:
parseErrorBlob(err: HttpErrorResponse): Observable<any> {
const reader: FileReader = new FileReader();
const obs = Observable.create((observer: any) => {
reader.onloadend = (e) => {
observer.error(JSON.parse(reader.result));
observer.complete();
}
});
reader.readAsText(err.error);
return obs;
}
and use it like this:
public fetchBlob(): Observable<Blob> {
return this.http.get(
'my/url/to/ressource',
{responseType: 'blob'}
).pipe(catchError(this.parseErrorBlob))
}
The answer by SplitterAlex mentions the Angular issue but doesn't mention a very nice solution provided there by JaapMosselman that involves creating an HttpInterceptor
that will translate the Blob back to JSON.
This way, you don't have to implement this throughout your application, and when the issue is fixed, you can simply remove it.
import { Injectable } from '@angular/core';
import { HttpInterceptor, HttpHandler, HttpRequest, HttpEvent, HttpErrorResponse } from '@angular/common/http';
import { Observable, throwError } from 'rxjs';
import { catchError } from 'rxjs/operators';
@Injectable()
export class BlobErrorHttpInterceptor implements HttpInterceptor {
public intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
return next.handle(req).pipe(
catchError(err => {
if (err instanceof HttpErrorResponse && err.error instanceof Blob && err.error.type === "application/json") {
// https://github.com/angular/angular/issues/19888
// When request of type Blob, the error is also in Blob instead of object of the json data
return new Promise<any>((resolve, reject) => {
let reader = new FileReader();
reader.onload = (e: Event) => {
try {
const errmsg = JSON.parse((<any>e.target).result);
reject(new HttpErrorResponse({
error: errmsg,
headers: err.headers,
status: err.status,
statusText: err.statusText,
url: err.url
}));
} catch (e) {
reject(err);
}
};
reader.onerror = (e) => {
reject(err);
};
reader.readAsText(err.error);
});
}
return throwError(err);
})
);
}
}
Declare it in your AppModule or CoreModule:
import { HTTP_INTERCEPTORS } from '@angular/common/http';
...
@NgModule({
...
providers: [
{
provide: HTTP_INTERCEPTORS,
useClass: BlobErrorHttpInterceptor,
multi: true
},
],
...
export class CoreModule { }
The code from SplitterAlex worked for me but I needed the error object and the status code too. Thats why I adjusted the parseErrorBlob method a little bit.
public parseErrorBlob(err: HttpErrorResponse): Observable<any> {
const reader: FileReader = new FileReader();
const obs = new Observable((observer: any) => {
reader.onloadend = (e) => {
const messageObject = JSON.parse(reader.result as string);
observer.error({
error : {
message : messageObject.message
},
message : messageObject.message,
status : err.status
});
observer.complete();
};
});
reader.readAsText(err.error);
return obs;
}
It can also be done with: error.text()
this.dataService
.getFile()
.subscribe((response) => {
FileSaver.saveAs(response.body, 'file.txt');
}, async (error) => {
const message = JSON.parse(await error.error.text()).message;
this.toast.error(message, 'Error');
});
If you're usung RxJS you can use something like this:
catchError((response: HttpErrorResponse) => {
return !!this.isBlobError(response) ? this.parseErrorBlob(response) : throwError(response);
})
and after that you can chain other catchError and do your stuff.
Here are the methods:
isBlobError(err: any) {
return err instanceof HttpErrorResponse && err.error instanceof Blob && err.error.type === 'application/json';
}
parseErrorBlob(err: HttpErrorResponse): Observable<any> {
const reader: FileReader = new FileReader();
const obs = new Observable((observer: any) => {
reader.onloadend = (e) => {
observer.error(new HttpErrorResponse({
...err,
error: JSON.parse(reader.result as string),
}));
observer.complete();
};
});
reader.readAsText(err.error);
return obs;
}