Javascript Angular 5/6:处理从ASP.NET核心API HTTP下载的文件(带友好的文件名)

Javascript Angular 5/6:处理从ASP.NET核心API HTTP下载的文件(带友好的文件名),javascript,c#,angular,typescript,asp.net-core,Javascript,C#,Angular,Typescript,Asp.net Core,我目前有一个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 F

我目前有一个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" };
}
我可以通过邮递员测试它,它返回一个带有正确数据的CSV,没有问题

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

我的问题:最新的Angular真的没有办法开箱即用吗?我不是一个角度专家,但我认为应该有一个例子,或者一些内置的机制,将下载的文件提供给浏览器。然而,似乎有很多黑客参与其中

我当前的WIP解决方案确实会将文件返回到浏览器进行下载,但不管API中指定的文件名如何,都会将其作为临时文件名(某些看起来像GUID的东西)下载:

下面是我的组件类和服务类中的内容。我更新了
downloadFile()
方法,以使用中提供的答案使友好的文件名正常工作,但我还是希望找到一个不那么麻烦的解决方案

// 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);
}
//组件
下载报告(选项:报告选项){
this._service.getCSV(options).subscribe(数据=>this.downloadFile(数据));
}
下载文件(blob:blob){
常量文件名='report.csv';
if(navigator.msSaveBlob){
//IE 10+
msSaveBlob(blob,文件名);
}否则{
const link=document.createElement('a');
const url=url.createObjectURL(blob);
link.setAttribute('href',url);
link.setAttribute('下载',文件名);
link.style.visibility='hidden';
document.body.appendChild(链接);
link.click();
document.body.removeChild(link);
revokeObjectURL(URL);
}
}
//服务

getCSV(reportOptions:reportOptions):可观察的解决方案)。有更好的办法吗?一种“最佳实践”的方式?

这就是我使用的方式。它基本上和你正在使用的是一样的东西,但在我看来,用锚输入看起来更干净一些。我花了很长时间研究了正确的方法,却找不到一种非黑客的方法

  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);
        }
      });
  }

我认为没有现成的解决方案。使用
createObjectURL
,查看这是否有助于创建用户友好的文件名:@David谢谢!我现在使用它来生成名称。还是要把这个问题留给大家,看看是否有一些模糊的角度-y的方法来做到这一点。