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 causing problem with my error handling.
this.httpClient.get('http://m502126:3000/reports/perdate', {
observe: 'body',
responseType: 'blob',
params: new HttpParams().set('START_DATE', startDate)
.set('END_DATE', endDate)
.set('MIXER', mixer)
.set('ATTACH', 'true')
}).subscribe(data => {
console.log(data);
},
error => {
console.log(error);
}
)
the problem is i am setting request type as'blob' and type of error is any . So when error comes and goes in error block the response type remains 'blob'. How to handle this ?
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))
}
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');
});
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 { }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With