前端文件下载(四)

截止目前,我们已经分了三个篇幅讲解了前端文件的下载。

本文,我们以文章 前端文件下载(三) 为基础来扩展讲解通过第三方库下载大文件。

我们为什么不对原生的进行封装呢?我们当然可以对原生进行封装,但是有现成成熟的库,我们为什么不用呢?

案例使用的代码来源 前端文件下载(三),开发环境不变,服务端的代码不做变更。

axios

axios 是很受欢迎的 JavaScript 库,是基于 promiseHTTP 客户端,适用于浏览器和 nodejs

我们在前端模版上做些更改:

html 复制代码
<!DOCTYPE html>
<html>
<head>
  <title>SSR Download File</title>
  <!-- import -->
  <script src="https://unpkg.com/axios/dist/axios.min.js"></script>
</head>
<body>
  <h1>Hello, Jimmy!</h1>
  <button id="download">Download File</button>
  <div style="display: flex; align-items: center;">
    <span>Downloading progress:</span>
    <progress id="progress" value="0" max="100"></progress>
    <span id="progressVal">0%</span>
  </div>
  <script>
    (function(){

      let downloadBtn = document.getElementById("download");
      let progressDom = document.getElementById("progress");
      let progressValDom = document.getElementById("progressVal");
      let hintDom = document.getElementById('hint');

      downloadBtn.addEventListener('click', function(){
        axios({
          method: 'get',
          url: '/download/file',
          responseType: 'blob',  // set to blob
          onDownloadProgress: function(progressEvent) {
            const percent_complete = ((progressEvent.loaded / progressEvent.total) * 100).toFixed(2);
            progressDom.value = percent_complete;
            progressVal.innerText = percent_complete + '%';
          }
        })
          .then(response => {
            const downloadLink = document.createElement('a');
            downloadLink.href = URL.createObjectURL(response.data); // createObjectURL
            downloadLink.download = 'demo.zip'; // should add, or filename extension not work
            downloadLink.click();
            URL.revokeObjectURL(downloadLink.href); // revoke
          })
          .catch(error => {
            // handle error
            console.error(error);
          });
      })
    })()
  </script>
</body>
</html>

我们做了下面的更改:

  • header 中引入 axios
  • axios 调用替换原生的 XMLHttpRequest

上面的调用方式,中规中矩,多多少少看到原生调用的影子,比如 responseType: 'blob'onDownloadProgress

@angular/common/http

axiosreactvue 框架开发的时,用的比较频繁。笔者使用的 angular 框架来开发,其中集成了 @angular/common/http。那么,它又是如何像 axios 调用文件下载的呢?

我们简单写了个 demo,如下:

html 复制代码
<!-- demo.component.html -->
<button
    type="button"
    class="btn btn-primary"
    (click)="downloadDemo()">
  <fa-icon [icon]="faDownload"></fa-icon>
  <span>download demo</span>
</button>

上面生成了一个调用下载接口的按钮。

我们简单生成一个服务类:

typescript 复制代码
// demo.service.ts
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';

@Injectable()
export class DemoService {
  constructor(
    protected http: HttpClient
  ){}
  
  public dowloadFile(url: string): Observable<any> {
    return this.http.get(
      url,
      {
        observe: 'events',
        reportProgress: true, // trigger progress
        responseType: 'blob'
      }
    );
  }
}

接着我们调用服务:

typescript 复制代码
// demo.component.ts
import { Component, OnInit } from '@angular/core';
import { faDownload } from '@fortawesome/free-solid-svg-icons';
import { DemoService } from 'path/to/demo.service.ts';

@Component({
  selector: 'demo',
  templateUrl: './demo.component.html',
  styleUrls: ['./demo.component.css']
})
export class DemoComponent implements OnInit {
  public faDownload = faDownload;
  
  constructor(
    protected demoService: DemoService
  ){}
  
  ngOnInit(): void {
  }
  
  public downloadDemo(): void {
    let url = 'http://localhost:3000/download/file';
    this.demoService.downloadFile(url).subscribe({
      next: (event: any) => {
        if (event.type === HttpEventType.DownloadProgress) {
          // progress notify
          const percentDone = Math.round(100 * event.loaded / event.total);
          console.log(`File is ${percentDone}% downloaded.`);
        } else if (event.type === HttpEventType.Response) {
          // HTTP response finish
          const downloadLink = document.createElement('a');
          downloadLink.href = URL.createObjectURL(event.body); // createObjectURL
          downloadLink.download = 'demo.zip'; // should add, or filename extension not work
          downloadLink.click();
          URL.revokeObjectURL(downloadLink.href); // revoke
        }
      }
    })
  }
}

这里我们采用了跨域来请求接口,读者可前往 【案例】同源策略 - CORS 处理 了解。

同理,我们这里也设置了 responseType ,开启 progress -〉 reportProgress,并设定 responseType: 'blob'。不同的库大同小异,就看开发需要和团队要求来使用。

总结

  • 使用原生 XMLHttpRequest 处理请求,让我们知道文件下载的前后发生了什么;使用 axios@angular/common/http 能让我们更好管理和快速开发
  • axios 也好,@angular/common/http 也罢,大同小异,看团队来使用

关于前端文件下载,我们就讲到这里。后面我们会讲讲文件上传

相关推荐
香蕉可乐荷包蛋1 小时前
浅入ES5、ES6(ES2015)、ES2023(ES14)版本对比,及使用建议---ES6就够用(个人觉得)
前端·javascript·es6
未来之窗软件服务2 小时前
资源管理器必要性———仙盟创梦IDE
前端·javascript·ide·仙盟创梦ide
my_styles2 小时前
docker-compose部署项目(springboot服务)以及基础环境(mysql、redis等)ruoyi-ry
spring boot·redis·后端·mysql·spring cloud·docker·容器
liuyang___3 小时前
第一次经历项目上线
前端·typescript
西哥写代码3 小时前
基于cornerstone3D的dicom影像浏览器 第十八章 自定义序列自动播放条
前端·javascript·vue
清风细雨_林木木3 小时前
Vue 中生成源码映射文件,配置 map
前端·javascript·vue.js
免檒4 小时前
go语言协程调度器 GPM 模型
开发语言·后端·golang
FungLeo4 小时前
node 后端和浏览器前端,有关 RSA 非对称加密的完整实践, 前后端匹配的代码演示
前端·非对称加密·rsa 加密·node 后端
不知道写什么的作者4 小时前
Flask快速入门和问答项目源码
后端·python·flask
雪芽蓝域zzs4 小时前
JavaScript splice() 方法
开发语言·javascript·ecmascript