【问题标题】:Angular 5/6: Handle File Download (w/Friendly File Name) from ASP.NET Core API HTTPAngular 5/6:从 ASP.NET Core API HTTP 处理文件下载(带有友好文件名)
【发布时间】:2019-02-12 19:40:07
【问题描述】:

我目前有一个 ASP.NET Core 2.1 API 端点,用户可以点击它来下载 CSV 文件:

[HttpPost("Gimme")]
public IActionResult Gimme([FromBody] MyOptions options)
{
    MemoryStream reportStream = _reportGenerator.GenerateReportStream(options.StartDate, options.EndDate);

    return new FileStreamResult(reportStream, "text/csv") { FileDownloadName = "report.csv" };
}

我可以通过 POSTMan 对其进行测试,它会返回一个包含正确数据的 CSV,没问题。

输入 Angular。我们与 API 交互的网站使用 Angular 驱动的单页应用程序。我已经搜索了有关如何处理来自 API 端点的文件的各种方法,并且似乎很多都围绕着获取 Blob 和创建一个内联 URL,然后通过 JavaScript 中的window.open() 导航到该 URL。或者在内存中创建a 标签,然后调用click()

我的问题:最新的 Angular 真的没有办法开箱即用地处理这个问题吗?我不是 Angular 专家,但我认为their site 上会有一个示例或一些用于将下载文件提供给浏览器的内置机制。然而,似乎只是涉及很多黑客行为。

我当前的 WIP 解决方案确实将文件返回到浏览器以供下载,但无论 API 中指定的文件名如何,它都会作为临时文件名(一些类似于 GUID 的东西)下载:

以下是我的组件和服务类中的内容。我更新了downloadFile() 方法以使用this SO answer 中提供的答案来获得友好的文件名,但我仍然宁愿找到一个不那么hacky 的解决方案。

// Component

DownloadReport(options: ReportOptions) {
    this._service.getCSV(options).subscribe(data => this.downloadFile(data));
}

downloadFile(blob: Blob) {
    const fileName = 'report.csv';
    if (navigator.msSaveBlob) {
        // IE 10+
        navigator.msSaveBlob(blob, fileName);
    } else {
        const link = document.createElement('a');
        const url = URL.createObjectURL(blob);
        link.setAttribute('href', url);
        link.setAttribute('download', fileName);
        link.style.visibility = 'hidden';
        document.body.appendChild(link);
        link.click();
        document.body.removeChild(link);
        URL.revokeObjectURL(url);
    }
}

// Service

getCSV(reportOptions: ReportOptions): Observable<any> {
    let headers = new HttpHeaders();
    headers = headers.set('Accept', 'text/csv');
    return this._httpClient
        .post(`${this.apiRoot}/Gimme`, reportOptions, { headers: headers, responseType: 'blob' })
        .catch(this.handleError);
}

如您所见,我目前正在实施createObjectURL hack 以使其正常工作(Found On Internet 解决方案的混搭)。有没有更好的办法? “最佳实践”之类的方式?

【问题讨论】:

  • 我不认为有任何开箱即用的解决方案。看看这是否有助于使用createObjectURLstackoverflow.com/a/51635727/1160794
  • @David 谢谢!我现在正在使用它来生成名称。仍然会留下问题,看看是否有一些晦涩难懂的 An​​gular-y 方法来做到这一点。

标签: javascript c# angular typescript asp.net-core


【解决方案1】:

这是我使用的。它与您使用的基本相同,但使用 Anchor 打字对我来说看起来更干净一些。我研究了很长时间的正确方法,但找不到一种非 hacky 的方法。

  download(): void {
    this.service.getFile({ id: id, name: name })
      .subscribe(data => {
        if (window.navigator && window.navigator.msSaveOrOpenBlob) {
          //save file for IE
          window.navigator.msSaveOrOpenBlob(data, name);
        } else {
          const objectUrl: string = URL.createObjectURL(data);
          const a: HTMLAnchorElement = document.createElement('a') as HTMLAnchorElement;

          a.href = objectUrl;
          a.download = name;
          document.body.appendChild(a);
          a.click();

          document.body.removeChild(a);
          URL.revokeObjectURL(objectUrl);
        }
      });
  }

【讨论】:

    猜你喜欢
    • 2019-02-08
    • 1970-01-01
    • 1970-01-01
    • 2019-01-18
    • 1970-01-01
    • 2020-06-21
    • 2019-05-12
    • 2022-10-13
    • 2019-01-08
    相关资源
    最近更新 更多