如何使用 Angular 中浏览器的本机下载小部件以编程方式下载文件?

Rom*_*n-p 5 javascript blob stream typescript angular

因此,当我请求我的网络服务下载 zip 文件时,它会秘密下载文件内容,突然间,该文件出现在下载任务栏中,但已下载完整(100%)

使用以下角度方法:


const endpoint = "http://localhost:8080/download/zip"
this.http.get<Blop>(endpoint, {headers: httpHeaders, responseType: 'blob', reportProgress: true })

Run Code Online (Sandbox Code Playgroud)

这就是我的订阅方式:

this.http.get<Blop>(endpoint, {headers: httpHeaders, responseType: 'blob', reportProgress: true }).subscribe({
  next: data => {
    console.log('blocking or not');
    const blob = new Blob([data as any], { type: 'application/zip' });
    window.location.href = URL.createObjectURL(blob);
  }
})
Run Code Online (Sandbox Code Playgroud)

所以我注意到 myconsole.log(...)直到下载结束才被调用,所以我认为浏览器用户界面无法检测到下载,直到它到达window.location.href.

如何强制传输结束前将下载显示在下载任务栏中,并在浏览器中查看下载进度?我找不到任何与异步 blop 或类似内容相关的内容。

PS:我的后端正在提供数据流,所以后端不是问题。当通过浏览器直接调用我的api时,我们可以在下载任务栏中看到下载进度。不过,如果你们感兴趣,这是片段(spring-boot)

    @GetMapping("/download/zip")
    fun download(response: HttpServletResponse): StreamingResponseBody {
        val file = downloads.download("launcher")

        response.contentType = "application/zip"
        response.setHeader(
            "Content-Disposition",
            "attachment;filename=sample.zip"
        )
        response.setContentLengthLong(file.length())

        return StreamingResponseBody { outputStream: OutputStream ->
            var bytesRead: Int
            val buffer = ByteArray(2048)
            val inputStream: InputStream = file.inputStream()
            while (inputStream.read(buffer).also { bytesRead = it } != -1) {
                outputStream.write(buffer, 0, bytesRead)
            }
        }
    }
Run Code Online (Sandbox Code Playgroud)

Pet*_*nov 5

下载有2种方式:

  1. http.get + msSaveOrOpenBlob(如果已定义)/createObjectURL
  • 您可以完全控制请求、流程和错误。例如,您可以取消请求、添加附加标头等。
  • 下载保留在您的应用程序流程中,例如 F5 将取消它。
  1. 创建隐藏的下载链接并以编程方式单击它
  • 你不能添加标题,你不能以简单的方式显示进度/错误(有一些技巧涉及BE设置的额外cookie)
  • 它被视为单独的进程,例如您可以关闭应用程序选项卡或其他任何内容。

似乎没有机会混合这两种方法,一般来说,我会说第一种方法更现代,更适合小文件,但是如果您对此不满意,请尝试第二种方法(https://stackoverflow.com/a/ 49917066/4019404):

function download(url) {
  const a = document.createElement('a')
  a.href = url
  a.download = url.split('/').pop()
  document.body.appendChild(a)
  a.click()
  document.body.removeChild(a)
}
Run Code Online (Sandbox Code Playgroud)