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

How do I programmatically download a file using the browser's native download widget in Angular?

所以,当我请求我的网络服务下载一个 zip 文件时,它会偷偷下载文件内容,突然间,该文件出现在下载任务栏中但已经下载完整 (100%)

使用以下 angular 方法:


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

我是这样订阅的:

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

所以我注意到我的 console.log(...) 直到下载结束才被调用,所以我想浏览器-ui 在下载到达 [=15= 之前无法检测到下载].

如何强制下载结束前显示在下载任务栏,并在浏览器中查看下载进度?我找不到与异步 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)
            }
        }
    }

假设您使用的是 Angular 的 HttpClient,像这样的东西应该可以工作:

    const endpoint = "http://localhost:8080/download/zip"
    const req = new HttpRequest('GET', endpoint, { reportProgress: true, })
    this.Http.request(req).subscribe(event => {
      if (event.type === HttpEventType.DownloadProgress) {
        const percentDone = Math.round(100 * event.loaded / (event.total || 0))
        console.log(percentDone);
      } else if (event instanceof HttpResponse) {
        const blob = new Blob([event.body as any], { type: 'application/zip' });
        window.location.href = URL.createObjectURL(blob);
      }
    })

下载有两种方式:

  1. http.get + msSaveOrOpenBlob(如果已定义)/createObjectURL
  • 您可以完全控制请求、流程和错误。例如。你可以取消请求,添加额外的headers,等等
  • 下载仍在您的应用程序流程中,例如F5 将取消它。
  1. 创建隐藏下载 link 并以编程方式单击它
  • 你不能添加headers,你不能以简单的方式显示progress/errors(有一些技巧涉及额外的cookies由BE设置)
  • 它被描述为单独的过程,例如你可以关闭你的应用程序选项卡或其他任何东西。

似乎没有机会混合使用这两种方法,总的来说,我会说第一种更现代,更适合小文件,但是如果您对它不满意,请尝试第二种 (https://whosebug.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)
}

你可以简单地使用这个包

npm i ngx-filesaver

constructor(private _http: Http, private _FileSaverService: FileSaverService) {
}

onSave() {
  this._http.get('yourfile.png', {
    responseType: ResponseContentType.Blob // This must be a Blob type
  }).subscribe(res => {
    this._FileSaverService.save((<any>res)._body, fileName);
  });
}

在此处完成文档 ngx file saver 还有 file saver.js

从技术角度来看,您无法更改浏览器在后台接收文件的行为方式。相反,您可以通过在发出 HTTP 请求时将选项 observe 设置为 events 计算下载进度 。这样,您不仅会收到请求的最终响应主体,还会访问中间 HTTP 事件。 之后,您可以在浏览器之外显示自己的下载进度

Angular 中有多种 HTTP 事件,全部合并到 HttpEvent. We also need to explicitly pass the option reportProgress in order to receive HttpProgressEvents 类型下。 HTTP 请求最终将如下所示:

this.http.get(url, {
  reportProgress: true,
  observe: 'events',
  responseType: 'blob'
})

您可以在 angular file download progress 找到一个很好的实现。

试试这个:

$('a#someID').attr({target: '_blank', 
                    href  : 'http://localhost/directory/file.pdf'});

它使用jQuery

用户包https://www.npmjs.com/package/file-saver

npm i file-saver

然后在您的组件中,导入 SaveAs 方法

import { saveAs } from 'file-saver';


saveAs(url, name);