我有一个WebApi / MVC应用程序,我正在为它开发一个angular2客户端(以取代MVC)。我在理解Angular如何保存文件时遇到了一些麻烦。

请求是可以的(与MVC一起工作很好,我们可以记录接收到的数据),但我不知道如何保存下载的数据(我主要遵循与本文相同的逻辑)。我确信这是愚蠢的简单,但到目前为止,我根本没有领会它。

组件函数的代码如下。我尝试了不同的替代方案,blob方式应该是我所理解的方式,但URL中没有createObjectURL函数。我甚至不能在窗口中找到URL的定义,但显然它存在。如果我使用FileSaver.js模块,我得到同样的错误。所以我猜这是最近改变的或者还没有实现的东西。我如何触发文件保存在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);
}

为了完整起见,获取数据的服务如下所示,但它所做的唯一一件事是发出请求并在没有映射的情况下传递数据:

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

当前回答

定位12 +最高一个网站

您可以从服务器返回一个Blob对象,并创建一个锚标记,并将href属性设置为从Blob创建的对象URL。现在点击锚点将下载文件。您也可以设置文件名。

downloadFile(path: string): Observable<any> {
        return this._httpClient.post(`${environment.ApiRoot}/accountVerification/downloadFile`, { path: path }, {
            observe: 'response',
            responseType: 'blob'
        });
    }

saveFile(path: string, fileName: string): void {
            this._accountApprovalsService.downloadFile(path).pipe(
                take(1)
            ).subscribe((resp) => {
                let downloadLink = document.createElement('a');
                downloadLink.href = window.URL.createObjectURL(resp.body);
                downloadLink.setAttribute('download', fileName);
                document.body.appendChild(downloadLink);
                downloadLink.click();
                downloadLink.remove();
            });
            
        }

后端

[HttpPost]
[Authorize(Roles = "SystemAdmin, SystemUser")]
public async Task<IActionResult> DownloadFile(FilePath model)
{
    if (ModelState.IsValid)
    {
        try
        {
            var fileName = System.IO.Path.GetFileName(model.Path);
            var content = await System.IO.File.ReadAllBytesAsync(model.Path);
            new FileExtensionContentTypeProvider()
                .TryGetContentType(fileName, out string contentType);
            return File(content, contentType, fileName);
        }
        catch
        {
            return BadRequest();
        }
    }

    return BadRequest();

}

其他回答

这是我在我的案例中做的事情

// service method
downloadFiles(vendorName, fileName) {
    return this.http.get(this.appconstants.filesDownloadUrl, { params: { vendorName: vendorName, fileName: fileName }, responseType: 'arraybuffer' }).map((res: ArrayBuffer) => { return res; })
        .catch((error: any) => _throw('Server error: ' + error));
}

// a controller function which actually downloads the file
saveData(data, fileName) {
    var a = document.createElement("a");
    document.body.appendChild(a);
    a.style = "display: none";
    let blob = new Blob([data], { type: "octet/stream" }),
        url = window.URL.createObjectURL(blob);
    a.href = url;
    a.download = fileName;
    a.click();
    window.URL.revokeObjectURL(url);
}

// a controller function to be called on requesting a download
downloadFiles() {
    this.service.downloadFiles(this.vendorName, this.fileName).subscribe(data => this.saveData(data, this.fileName), error => console.log("Error downloading the file."),
        () => console.info("OK"));
}

解决方案从这里引用

我找到的答案要么是在Angular 13.1上无法运行,要么是不必要的复杂(就像被接受的例子一样),而且没有解释为什么这是必要的。 对于像Angular这样不断变化的生态系统来说,要求附加版本号是非常有用的。

用户@Aleksandar Angelov提供的迷你代码片段绕过了会话系统,因此需要进行不必要的授权。

根据他的回答,我得出了以下代码:

  downloadConfiguration(url: string, filename: string) {
    this.http.get(url, {responseType: 'blob'})
    .subscribe(data => {
      // console.log("data", data);
      var url = window.URL.createObjectURL(data);
      let downloadLink = document.createElement('a');
      downloadLink.href = url
      downloadLink.setAttribute('download', filename);
      downloadLink.click();
    });
  }

问题是可观察对象运行在另一个上下文中,所以当你尝试创建URL var时,你有一个空对象,而不是你想要的blob。

解决这个问题的众多方法之一如下:

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

当请求准备好时,它将调用函数"downloadFile",定义如下:

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

这个blob已经被完美地创建了,所以URL变量,如果没有打开新的窗口,请检查你已经导入'rxjs/Rx';

import 'rxjs/Rx' ;

我希望这能帮助到你。

对于较新的angular版本:

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


import {saveAs} from 'file-saver';

this.http.get('endpoint/', {responseType: "blob", headers: {'Accept': 'application/pdf'}})
  .subscribe(blob => {
    saveAs(blob, 'download.pdf');
  });

更新Hector的答案使用文件保护程序和HttpClient的第2步:

public downloadFile(file: File): Observable<Blob> {
    return this.http.get(file.fullPath, {responseType: 'blob'})
}