Pregunta ¿Cómo descargo un archivo con Angular2?


Tengo una aplicación WebApi / MVC para la cual estoy desarrollando un cliente angular2 (para reemplazar a MVC). Tengo algunos problemas para entender cómo Angular guarda un archivo.

La solicitud está bien (funciona bien con MVC, y podemos registrar los datos recibidos) pero no puedo encontrar la manera de guardar los datos descargados (estoy siguiendo la misma lógica que en esta publicación) Estoy seguro de que es estúpidamente simple, pero hasta ahora simplemente no lo estoy captando.

El código de la función componente está abajo. He intentado diferentes alternativas, la forma de blob debería ser el camino por recorrer hasta donde yo entendía, pero no hay ninguna función createObjectURL en URL. Ni siquiera puedo encontrar la definición de URL en la ventana, pero aparentemente existe. Si uso el FileSaver.js módulo Me sale el mismo error. Así que supongo que esto es algo que ha cambiado recientemente o aún no se ha implementado. ¿Cómo puedo activar el archivo guardado en A2?

downloadfile(type: string){

    let thefile = {};
    this.pservice.downloadfile(this.rundata.name, type)
        .subscribe(data => thefile = new Blob([data], { type: "application/octet-stream" }), //console.log(data),
                    error => console.log("Error downloading the file."),
                    () => console.log('Completed file download.'));

    let url = window.URL.createObjectURL(thefile);
    window.open(url);
}

En aras de la exhaustividad, el servicio que obtiene los datos está abajo, pero lo único que hace es emitir la solicitud y pasar los datos sin mapear si tiene éxito:

downloadfile(runname: string, type: string){
   return this.authHttp.get( this.files_api + this.title +"/"+ runname + "/?file="+ type)
            .catch(this.logAndPassOn);
}

Nota: Sé que este no es un ejemplo mínimo de trabajo, pero he puesto mucho esfuerzo en la descripción del problema. Si va a downvote por favor deje un comentario también.


75
2018-02-01 19:15


origen


Respuestas:


el problema es que la ejecución observable se lleva a cabo en otro contexto, por lo que cuando intentas crear la URL var tienes un objeto vacío y no el blob que deseas.

Una de las muchas formas que existen para resolver esto es la siguiente:

this._reportService.getReport().subscribe(data => this.downloadFile(data)),//console.log(data),
                 error => console.log("Error downloading the file."),
                 () => console.info("OK");

Cuando la solicitud esté lista llamará a la función "downloadFile" que se define de la siguiente manera:

downloadFile(data: Response){
  var blob = new Blob([data], { type: 'text/csv' });
  var url= window.URL.createObjectURL(blob);
  window.open(url);
}

el blob se ha creado perfectamente y, por lo tanto, si el URL var no abre la nueva ventana, verifique que ya haya importado 'rxjs / Rx';

  import 'rxjs/Rx' ;

Espero que esto le pueda ayudar.


79
2018-02-04 19:54



Tratar esta!

1 - Instalar dependencias para mostrar guardar / abrir archivo emergente

npm install file-saver --save
npm install @types/file-saver --save

2- Crea un servicio con esta función para recibir los datos

downloadFile(id): Observable<Blob> {
    let options = new RequestOptions({responseType: ResponseContentType.Blob });
    return this.http.get(this._baseUrl + '/' + id, options)
        .map(res => res.blob())
        .catch(this.handleError)
}

3- En el componente analizar el blob con 'file-saver'

import {saveAs as importedSaveAs} from "file-saver";

  this.myService.downloadFile(this.id).subscribe(blob => {
            importedSaveAs(blob, this.fileName);
        }
    )

Esto funciona para mi!


47
2018-05-11 10:24



Descargue la solución * .zip para angular 2.4.x: debe importar ResponseContentType de '@ angular / http' y cambiar responseType a ResponseContentType.ArrayBuffer (por defecto es ResponseContentType.Json)

getZip(path: string, params: URLSearchParams = new URLSearchParams()): Observable<any> {
 let headers = this.setHeaders({
      'Content-Type': 'application/zip',
      'Accept': 'application/zip'
    });

 return this.http.get(`${environment.apiUrl}${path}`, { 
   headers: headers, 
   search: params, 
   responseType: ResponseContentType.ArrayBuffer //magic
 })
          .catch(this.formatErrors)
          .map((res:Response) => res['_body']);
}

12
2018-02-12 14:58



Como se menciona por Alejandro Corredor es un simple error de alcance los subscribe se ejecuta de forma asíncrona y el open debe colocarse en ese contexto, de modo que los datos terminen de cargarse cuando activamos la descarga.

Dicho esto, hay dos formas de hacerlo. Como los documentos recomiendan que el servicio se encargue de obtener y mapear los datos:

//On the service:
downloadfile(runname: string, type: string){
  var headers = new Headers();
  headers.append('responseType', 'arraybuffer');
  return this.authHttp.get( this.files_api + this.title +"/"+ runname + "/?file="+ type)
            .map(res => new Blob([res],{ type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' }))
            .catch(this.logAndPassOn);
}

Luego, en el componente que acaba de suscribir y tratar con los datos asignados. Hay dos posibilidades El primero, como se sugirió en la publicación original, pero necesita una pequeña corrección como señala Alejandro:

//On the component
downloadfile(type: string){
  this.pservice.downloadfile(this.rundata.name, type)
      .subscribe(data => window.open(window.URL.createObjectURL(data)),
                  error => console.log("Error downloading the file."),
                  () => console.log('Completed file download.'));
  }

El segundo forma sería usar FileReader. La lógica es la misma, pero podemos esperar explícitamente a que FileReader cargue los datos, evitando el anidamiento y resolviendo el problema asincrónico.

//On the component using FileReader
downloadfile(type: string){
    var reader = new FileReader();
    this.pservice.downloadfile(this.rundata.name, type)
        .subscribe(res => reader.readAsDataURL(res), 
                    error => console.log("Error downloading the file."),
                    () => console.log('Completed file download.'));

    reader.onloadend = function (e) {
        window.open(reader.result, 'Excel', 'width=20,height=10,toolbar=0,menubar=0,scrollbars=no');
  }
}

Nota:Estoy tratando de descargar un archivo de Excel, y aunque la descarga se desencadena (por lo que esto responde a la pregunta), el archivo está dañado. Ver la respuesta a esta publicación para evitando el archivo corrupto


11
2018-02-05 15:35



Si no necesita agregar encabezados en la solicitud, para descargar un archivo en Angular2 puede hacer un simple:

window.location.href='http://example.com/myuri/report?param=x';

en tu componente.


11
2017-08-04 05:37



Esto es para personas que buscan cómo hacerlo usando HttpClient y File-Saver:

  1. Instalar archivo-protector

npm install file-saver --save

npm install @ types / file-saver --save

Clase de servicio API:

export() {
    return this.http.get(this.download_endpoint, 
        {responseType: 'blob'});
}

Componente:

import { saveAs } from 'file-saver';
exportPdf() {
    this.api_service.export().subscribe(data => saveAs(data, `pdf report.pdf`));
}

8
2018-01-29 14:13



La descarga de archivos a través de ajax siempre es un proceso doloroso y, en mi opinión, es mejor dejar que el servidor y el navegador realicen este trabajo de negociación del tipo de contenido.

Creo que es mejor tener

<a href="api/sample/download"></a> 

para hacerlo. Esto ni siquiera requiere la apertura de nuevas ventanas y cosas por el estilo.

El controlador MVC como en su muestra puede ser como el siguiente:

[HttpGet("[action]")]
public async Task<FileContentResult> DownloadFile()
{
    // ...
    return File(dataStream.ToArray(), "text/plain", "myblob.txt");
}

7
2018-01-20 05:13