无法在Angular4 GET响应中查看“Content-Disposition”标头

10

我在我的Angular应用程序中尝试下载一个pdf文件。服务器(JBoss)提供了一个具有

Content-type : application/pdf和Content-Disposition

头部设置为attachment的文件。

我可以在fiddler响应中很好地看到这些头。但是在我的subscribe回调中,我看不到相同的头。相反,标头包含两个属性,即:

_headers和_normalizedHeaders

在进行GET调用时,我做如下操作:

`this._http.get(url, {responseType: 'arraybuffer'}).subscribe((file: Response)=>{

    //Cant find headers in file here

});`

我还尝试将 responseType 设置为 RequestContentType.Blob,但也没有任何区别。

对于我的下载实现,我有一段代码,一直以来都可以用 AngularJS 下载附件。我只是在这里遇到了读取 Content-Disposition 标头的困难。

我还尝试设置 { observe : response },期望以此获得详细的响应。然而,由于某些原因,在 GET options 中不允许设置该属性。

我看到了许多 SO 上的答案,并尝试了其中大部分,但仍无法获取标头。

P.S:直接在浏览器上访问 API 可以下载文件,这意味着我的 Java 代码没有问题,这让我想知道上面的代码出了什么问题。

请求建议。

3个回答

16

在Evans的建议下,通过使用Access-Control-Expose-HeaderssetExposedHeaders,我可以实现以下文件下载。

在您的Java代码中,您需要暴露Access-Control-Expose-Headers,这可以通过CORS完成:

    CorsFilter corsFilter = new CorsFilter();
    corsFilter.setAllowedHeaders("Content-Type, Access-Control-Allow-Headers, Access-Control-Expose-Headers, Content-Disposition, 
    Authorization, X-Requested-With");
    corsFilter.setExposedHeaders("Content-Disposition");

这将在服务器响应中暴露所需的标头。

在您的客户端上,您可以使用以下确切代码处理响应:

    private processDownloadFile() {
              const fileUrl = this._downloadUrl;
              this.http.get(fileUrl, ResponseContentType.ArrayBuffer).subscribe( (data: any) => {
                const blob = new Blob([data._body], { type: data.headers.get('Content-Type')});
                const contentDispositionHeader = data.headers.get('Content-Disposition');
                if (contentDispositionHeader !== null) {
                    const contentDispositionHeaderResult = contentDispositionHeader.split(';')[1].trim().split('=')[1];
                    const contentDispositionFileName = contentDispositionHeaderResult.replace(/"/g, '');
                    const downloadlink = document.createElement('a');
                    downloadlink.href = window.URL.createObjectURL(blob);
                    downloadlink.download = contentDispositionFileName;
                    if (window.navigator.msSaveOrOpenBlob) {
                        window.navigator.msSaveBlob(blob, contentDispositionFileName);
                    } else {
                        downloadlink.click();
                    }
                }
              });
    }   

当然,我把所有内容都写在了一个地方。你可能想将各种回调函数模块化。

希望它能帮助某个人在某一天。


3
这对我很有帮助,谢谢。对于任何使用dotnet core的人,以下是我的解决方案,在startup.cs > ConfigureServices()中实现。services.AddCors(c => { c.AddPolicy("CorsPolicy", options => options.SetIsOriginAllowed(s => s.Contains("localhost")).AllowAnyMethod().AllowAnyHeader().WithExposedHeaders("Content-Disposition")); }); - bonnu18
很遗憾,msSaveOrOpenBlob已经被弃用了 :( https://developer.mozilla.org/en-US/docs/Web/API/Navigator/msSaveOrOpenBlob - Maidenless
这对我在Spring Boot 2.6.x中有效。我只需要添加 exposedHeaders(...)。谢谢。 - sunitkatkar

9

如果您的服务器发送任何自定义标头,以便在Angular(或任何其他Web应用程序)中访问它,那么它必须存在于 Access-Control-Expose-Headers 中,否则您的浏览器将不会将其传递给您的Angular应用程序,即使您的开发人员工具显示存在也无法检索它。


我正在使用Java进行编程,并且我将以下标头设置为我的CORS的一部分:corsFilter.setAllowedHeaders("Content-Type, Access-Control-Allow-Headers, Access-Control-Expose-Headers, Content-Disposition, Content-Length, Authorization, X-Requested-With"); 你有什么其他的建议吗? - Saurabh Tiwari
如果您仔细查看代码,您会注意到您只设置了 Access-Control-Allow-Headers,并将 Access-Control-Expose-Headers 包含在允许的标头中。我不确定 Java 中如何实现这一点,但我认为您应该像这样添加一些内容:corsFilter.setExposedHeaders("custom header, customer, header") - Evans M.
我在现有代码中添加了 corsFilter.setExposedHeaders("Content-Disposition, Content-Type");。这使得文件可以被下载。然而,令人惊讶的是,如果您单击下载的文件,它只会弹出一个窗口,显示“无法加载PDF文档”。这个问题你熟悉吗? - Saurabh Tiwari
感谢 @Evans:您的答案帮助我实现了所需的行为。我会发布一个详细的答案。 - Saurabh Tiwari

0

嗨,你可以试试这样

我们需要使用文件保存器(file-saver)这个包,你可以通过运行命令"npm install file-saver --save" 来进行安装。安装完成后,你可以尝试以下代码

public downloadCSVFile(){
this.downloadPdf().subscribe(
    (res) => {      
        saveAs(res,'test.pdf')
    }
);
}

public downloadPdf(): any {
   let url='your url'
   let headers = new Headers();
   headers.append('Authorization', 'JWT ' + localStorage.getItem('id_token'));
   return this.http.get(url,{  headers: headers,responseType: ResponseContentType.Blob }).map(
    (res) => {
        return new Blob([res.blob()], { type: 'application/pdf' })
    })


  }

你需要从后台(JBoss服务器)公开"Content-Disposition"头。

谢谢@Robert,虽然我不是在寻找外部模块来实现它。我发布了帮助我的代码。 - Saurabh Tiwari
好的,超级的 @SaurabhTiwari - Robert

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接