前端文件下载(四)

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

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

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

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

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 也罢,大同小异,看团队来使用

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

相关推荐
山山而川粤4 小时前
母婴用品系统|Java|SSM|JSP|
java·开发语言·后端·学习·mysql
过往记忆4 小时前
告别 Shuffle!深入探索 Spark 的 SPJ 技术
大数据·前端·分布式·ajax·spark
高兴蛋炒饭5 小时前
RouYi-Vue框架,环境搭建以及使用
前端·javascript·vue.js
m0_748240446 小时前
《通义千问AI落地—中》:前端实现
前端·人工智能·状态模式
ᥬ 小月亮6 小时前
Vue中接入萤石等直播视频(更新中ing)
前端·javascript·vue.js
玉红7776 小时前
R语言的数据类型
开发语言·后端·golang
夜斗(dou)6 小时前
node.js文件压缩包解析,反馈解析进度,解析后的文件字节正常
开发语言·javascript·node.js
恩爸编程7 小时前
纯 HTML+CSS+JS 实现一个炫酷的圣诞树动画特效
javascript·css·html·圣诞树·圣诞树特效·圣诞树js实现·纯js实现圣诞树
神雕杨7 小时前
node js 过滤空白行
开发语言·前端·javascript
网络安全-杰克7 小时前
《网络对抗》—— Web基础
前端·网络