Estoy trabajando en una aplicación Angular 5. Tengo que descargar un archivo de mi aplicación de fondo y para hacer esto simplemente invoco una función como esta:

public executeDownload(id: string): Observable<Blob> {
  return this.http.get(this.replaceUrl('app/download', denunciaId), {responseType: 'blob'}).map(result => {
    return result;
  });
}

Y para invocar el servicio de descarga solo invoco:

public onDownload() {
  this.downloadService.executeDownload(this.id).subscribe(res => {
    saveAs(res, 'file.pdf');
  }, (error) => {
    console.log('TODO', error);
    // error.error is a Blob but i need to manage it as RemoteError[]
  });
}

Cuando la aplicación de fondo está en un estado particular, en lugar de devolver un Blob, devuelve un HttpErrorResponse que contiene en su campo error una matriz de RemoteError. RemoteError es una interfaz que escribí para administrar errores remotos.

En la función catch, error.error es un Blob. ¿Cómo puedo traducir el atributo Blob en una matriz de RemoteError[]?

Gracias de antemano.

7
xcesco 25 mar. 2018 a las 22:19

3 respuestas

La mejor respuesta

Como en los documentos "La única forma de leer contenido de un Blob es usar un FileReader". https://developer.mozilla.org/en-US/docs/ Web / API / Blob.

EDITAR: si necesita parte de blob, puede hacer un corte, que devuelve un nuevo Blob, y luego usar el lector de archivos.

1
Vayrex 26 mar. 2018 a las 09:58

Se espera que la respuesta sea un Blob, pero aparentemente no es el caso. Para evitar este error, cambie el responseType de blob a arraybuffer.

public executeDownload(id: string): Observable<Blob> {
  return this.http.get(this.replaceUrl('app/download', denunciaId), {responseType: 'arraybuffer'}).map(result => {
    return result;
  });
}
0
Yassine Younes 12 jun. 2020 a las 09:50

Este es un Problema angular conocido, y en ese hilo JaapMosselman proporciona una solución muy agradable que implica creando un HttpInterceptor que traducirá el Blob de nuevo a JSON.

Con este enfoque, no tiene que hacer conversiones en toda su aplicación, y cuando se soluciona el problema, simplemente puede eliminarlo.

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 en su AppModule o CoreModule:

import { HTTP_INTERCEPTORS } from '@angular/common/http';
...

@NgModule({
    ...
    providers: [
        {
            provide: HTTP_INTERCEPTORS,
            useClass: BlobErrorHttpInterceptor,
            multi: true
        },
    ],
    ...
export class CoreModule { }
5
Marcos Dimitrio 16 ago. 2019 a las 19:23