我的问题类似于this one,但那是一篇过时的文章,没有太多的上下文或细节,所以这是我得到的:
当我的组件调用下载文件方法时,该方法又调用下载文件服务,该服务从我的API发出HTTP GET请求,该请求将blob流回到服务。
组件:
this.svc.getDownloadFile(fileID, fileName).subscribe(res => {
console.log(res);
});
}
服务:
getDownloadFile(fileId: number, fileName: string): Observable<any> {
return this.http.get(this.downloadFileUrl + "/" + fileId, {
reportProgress: true,
observe: "events",
headers: this.getHeaders(),
responseType: "blob"
});
}
问题在于,因为这是一个API调用,所以Blob通过XHR流传输,我可以在Chrome的“网络”标签中看到它的下载及其进度。我遇到的问题是,在Chrome(或任何浏览器)中下载文件时,通常会收到某种浏览器下载通知,这只会在整个响应完成后才会发生。
例如,我在数据库中有一个50MB的文件。用户单击一个链接以从Angular应用程序下载该文件,该组件调用该服务,该服务依次执行API调用,该API将从DB获取文件并将其作为Blob响应进行流式传输。 Angular接受此响应,等到它已下载所有50MB内容,然后显示下载对话框。
API正在返回Content Disposition标头以及内容长度,内容类型,文件名等。我已经在Google各处进行搜索,并在上下搜索了类似内容,我知道浏览器不会自动下载之所以像往常一样是因为请求是通过Angular传递的,并且浏览器不会自动假设所有的Blob XHR应该都已保存。
我尝试使用:https://www.npmjs.com/package/streamsaver 但是此程序包实际上仅处理已存储的文件,而不处理从API作为blob发送的文件。
答案 0 :(得分:1)
如果API返回了Content-Disposition
标头,则可以使用window.open(url)
,它应该可以正常下载。
如果由于要操作字节或类似操作而必须将其流式传输到Angular,则可以订阅HttpClient
的进度事件以报告自己的进度(see here)。
如果随后要将文件保存到用户磁盘,则可以使用file-saver软件包。
答案 1 :(得分:0)
所以对于有相同问题的人,我要做的是:
请记住,这是在我的工作设置中,我们有一个存储加密blob的数据库,一个API通过文件流将其提供给我们的角度应用程序。
如果您拥有未加密的API,则可以使用window.open(urlToFile)
或window.location.href(urlToFile)
用@Pace进行上述操作。
由于我的API需要通过标头中的Bearer令牌进行授权,因此我创建了一个端点,该端点将检查令牌以及所请求的文件ID。然后,API创建一个GUID(或唯一的种类ID),并将GUID和文件ID一起存储在一个列表中,然后将其与到期时间一起存储在MemoryCache中。
完成此操作后,将返回带有已创建GUID的Ok响应。我不是安全专家,但是我认为这可能会为它提供安全性,原因如下:我确信这不是一个完美的解决方案:
GUID返回到Angular应用程序,然后在GUID返回之后调用window.location.href
并将其设置为通过GUID和文件ID的另一个端点。
此端点配置为不需要身份验证,并且仅允许下载列表中带有正确GUID的文件。
例如,这是我的服务被调用:
getDownloadFile(fileId: number): Observable<any> {
return this.http
.get(this.downloadFileUrl + "/" + fileId, {
headers: this.getHeaders() //Attaches bearer token
})
.pipe(
tap(res => { //res = the GUID being returned from API
window.location.href =
this.downloadFileUrl + "/temp/" + fileId + "/" + res;
})
);
}
如您所见,它调用已验证的端点,取回GUID,并立即使用GUID和文件ID将当前浏览器窗口的url设置为临时端点。请注意,由于这是正确设置了内容处置的文件流或Blob,因此它不会离开Angular应用程序,因此只能通过下载管理器开始下载。
这是我发现的唯一方法,它允许浏览器正常处理来自流API端点的下载。
大多数较小的文件并不重要,因为它们通过API下载得如此之快,以至于您通常一眨眼就看不到下载是在一开始还是没有开始,但是对于大文件如果您仅通过XHR进行API调用,则用户将没有任何指示,表明文件正在下载,直到请求完成,然后BAM!突然之间,您的下载文件中就会出现150MB的文件。这也是一种不错的方法,因为即使您离开Angular应用程序,它也会继续下载,这与常规API XHR订阅不同,后者将随该应用程序结束。 我还发现了如何点按具有Blob的XHR请求并跟踪进度,但是您将不得不在Angular应用程序中创建自己的下载管理器,而不使用大多数用户期望的默认浏览器。