How do I download a file with Angular2

2019-01-01 10:23发布

I have a WebApi / MVC app for which I am developing an angular2 client (to replace MVC). I am having some troubles understanding how Angular saves a file.

The request is ok (works fine with MVC, and we can log the data received) but I can't figure out how to save the downloaded data (I am mostly following the same logic as in this post). I am sure it is stupidly simple, but so far I am simply not grasping it.

The code of the component function is below. I've tried different alternatives, the blob way should be the way to go as far as I understood, but there is no function createObjectURL in URL. I can't even find the definition of URL in window, but apparently it exists. If I use the FileSaver.js module I get the same error. So I guess this is something that changed recently or is not yet implemented. How can I trigger the file save in 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);
}

For the sake of completeness, the service that fetches the data is below, but the only thing it does is to issue the request and pass on the data without mapping if it succeeds:

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

19条回答
回忆,回不去的记忆
2楼-- · 2019-01-01 10:53

This is for folks looking how to do it using HttpClient and file-saver:

  1. Install file-saver

npm install file-saver --save

npm install @types/file-saver --save

API Service class:

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

Component:

import { saveAs } from 'file-saver';
exportPdf() {
    this.api_service.export().subscribe(data => saveAs(data, `pdf report.pdf`));
}
查看更多
查无此人
3楼-- · 2019-01-01 10:53

To download and show PDF files, a very similar code snipped is like below:

  private downloadFile(data: Response): void {
    let blob = new Blob([data.blob()], { type: "application/pdf" });
    let url = window.URL.createObjectURL(blob);
    window.open(url);
  }

  public showFile(fileEndpointPath: string): void {
    let reqOpt: RequestOptions = this.getAcmOptions();  //  getAcmOptions is our helper method. Change this line according to request headers you need.
    reqOpt.responseType = ResponseContentType.Blob;
    this.http
      .get(fileEndpointPath, reqOpt)
      .subscribe(
        data => this.downloadFile(data),
        error => alert("Error downloading file!"),
        () => console.log("OK!")
      );
  }
查看更多
千与千寻千般痛.
4楼-- · 2019-01-01 10:56

I am using Angular 4 with the 4.3 httpClient object. I modified an answer I found in Js' Technical Blog which creates a link object, uses it to do the download, then destroys it.

Client:

doDownload(id: number, contentType: string) {
    return this.http
        .get(this.downloadUrl + id.toString(), { headers: new HttpHeaders().append('Content-Type', contentType), responseType: 'blob', observe: 'body' })
}

downloadFile(id: number, contentType: string, filename:string)  {

    return this.doDownload(id, contentType).subscribe(  
        res => { 
            var url = window.URL.createObjectURL(res);
            var a = document.createElement('a');
            document.body.appendChild(a);
            a.setAttribute('style', 'display: none');
            a.href = url;
            a.download = filename;
            a.click();
            window.URL.revokeObjectURL(url);
            a.remove(); // remove the element
        }, error => {
            console.log('download error:', JSON.stringify(error));
        }, () => {
            console.log('Completed file download.')
        }); 

} 

The value of this.downloadUrl has been set previously to point to the api. I am using this to download attachments, so I know the id, contentType and filename: I am using an MVC api to return the file:

 [ResponseCache(Location = ResponseCacheLocation.None, NoStore = true)]
    public FileContentResult GetAttachment(Int32 attachmentID)
    { 
        Attachment AT = filerep.GetAttachment(attachmentID);            
        if (AT != null)
        {
            return new FileContentResult(AT.FileBytes, AT.ContentType);  
        }
        else
        { 
            return null;
        } 
    } 

The attachment class looks like this:

 public class Attachment
{  
    public Int32 AttachmentID { get; set; }
    public string FileName { get; set; }
    public byte[] FileBytes { get; set; }
    public string ContentType { get; set; } 
}

The filerep repository returns the file from the database.

Hope this helps someone :)

查看更多
弹指情弦暗扣
5楼-- · 2019-01-01 10:56

Update to Hector's answer using file-saver and HttpClient for step 2:

public downloadFile(file: File): Observable<Blob> {
    return this.http.get(file.fullPath, {responseType: 'blob'})
}
查看更多
残风、尘缘若梦
6楼-- · 2019-01-01 10:58

Try this!

1 - Install dependencies for show save/open file pop-up

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

2- Create a service with this function to recive the data

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- In the component parse the blob with 'file-saver'

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

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

This works for me!

查看更多
君临天下
7楼-- · 2019-01-01 11:02

For newer angular versions:

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


import {saveAs} from 'file-saver/FileSaver';

this.http.get('endpoint/', {responseType: "blob", headers: {'Accept': 'application/pdf'}})
  .subscribe(blob => {
    saveAs(blob, 'download.pdf');
  });
查看更多
登录 后发表回答