常见文件下载与上传方式整理

前言

常见文件下载与上传方式。持续整理更新中,欢迎各位反馈。

下载篇

1. <a> 标签

最简单的方法莫过于使用 <a>download 属性进行下载,只需要一个链接即可完成下载操作。

html 复制代码
<a href="https://example.com/files/sample.pdf" download="sample.pdf">点击下载</a>

属性解释:

  • href :指明将要下载文件的url链接。
  • download :告诉浏览器将文件下载到本地,而不是在浏览器中打开。部分浏览器能够识别该属性值作为文件名使用。

优缺点:

  • 优点:使用简单,只需要一个url即可完成下载。
  • 缺点:不适用于动态生成或处理文件的情况。需要是同源。

2. window.location / window.open

<a> 标签下载一样使用简单。但比起它更具优势,能够屏蔽它的一部分缺点。同时更灵活一些,能够适用于动态生成文件或需要特殊处理的文件。

js 复制代码
window.location.href = 'https://example.com/files/sample.pdf';

window.open('https://example.com/files/sample.pdf');
  • 优点:适用简单的文件下载需求。
  • 缺点:无法提供更多的下载控制或处理,比如下载进度等。

3. fetch / XMLHttpRequest

如果想要更加细致地控制下载过程。例如下载前对文件进行处理,又或者是服务端动态生成文件。再加上 fetch 已经成为常见的请求方式,此时可以使用 fetch / XMLHttpRequest 获取流文件,再结合 Blob 对流文件进行下载保存。示例如下,其中 saveBlob 可见于个人笔记 如何将文本内容保存为文件

XMLHttpRequest 方式下载文件:
js 复制代码
const url = 'https://example.com/files/sample.pdf';

const xhr = new XMLHttpRequest();
const percent = 0;

xhr.open('GET', url, true);
xhr.responseType = 'blob';

xhr.onload = () => {
    const blob = xhr.response;
    
    saveBlob(blob, 'sample.pdf');
};

// XMLHttpRequest 下载文件能够实现进度监听
xhr.addEventListener('progress', (e) => {
    percent = e.loaded / e.total;
});

xhr.send();
fetch 方式下载文件:
js 复制代码
const url = 'https://example.com/files/sample.pdf';

const response = await fetch(url);
const blob = response.blob();

saveBlob(blob, 'sample.pdf');

fetchXMLHttpRequest都能实现下载进度监听。fetch 下载方式的进度监听可以参考文章 fetch 下载文件 + 显示进度 ,感谢作者 BigLu 对此的整理。

  • 优点:能够更加细致的控制下载过程。能够感知下载进度。fetch 方法已经被各大浏览器厂商支持,适配度不错。适用于服务端动态生成文件的下载,服务的不需要对该文件副本进行保存,可以节约服务器资源。
  • 缺点:相对前两种下载方式会比较复杂。下载过程中会用到 BlobURL.createObjectURL,在 IE 中存在兼容性问题。

4. iframe 下载

特定场景下适用,如后台下载。

js 复制代码
const url = 'https://example.com/files/sample.pdf';
const iframe = document.createElement('iframe');

iframe.style.display = 'none';
iframe.src = url;

document.body.appendChild(iframe);

创建一个隐藏的 <iframe> 标签,将标签的 src 属性设置为下载链接。该方法是将文件下载视为浏览器默认行为,不需要用户干预。

5. WebSocket 实时下载

鉴于前面的下载方式,我们可以通过与后台交互,让服务端发送 blob 流式文件,可以实现动态的文件下载。于是乎,在某些特殊场景,比如对日志服务器的文件进行实时的更新与下载。所以考虑使用 WebSocket 长连接实现对文件的实时下载。

js 复制代码
const wss = 'wss://example.com/log-updates';
const socket = new WebSocket(wss);

socket.addEventListener('message', event => { 
const fileData = event.data; // 文件数据,可以是Blob或ArrayBuffer
const filename = 'log.txt'; 

saveBlob(fileData, filename);

6. 三方库 downloadjs

使用三方库 downloadjs 进行文件下载。下载内容可以是 URL字符串Blob 或类型化的 数据数组 ,或者通过将文件数据表示为 base64 或 url 编码字符串的 dataURL

无论输入格式如何,download() 都使用指定的 文件名mime 信息以与使用 Content-Disposition HTTP 标头的服务器相同的方式保存文件。

下载 downloadjs
shell 复制代码
npm install downloadjs
使用方法

download(data, strFileName, strMimeType);

  • data:下载的数据内容,可以是 BlobFileStringdataURL
  • strFileName:要创建的文件的名称。
  • strMimeType:要下载的文件的 MIME 内容类型。
项目中使用 downloadjs
js 复制代码
import download from "downloadjs";

// ### 文本
// 字符串
download("hello world", "dlText.txt", "text/plain");
// dataURL 文本实例
download("data:text/plain,hello%20world", "dlDataUrlText.txt", "text/plain");
// blob 文本实例
download(new Blob(["hello world"]), "dlTextBlob.txt", "text/plain");
// url 实例
download("/robots.txt");
// UInt8 文本数组实例
const str = "hello world";
const arr = new Uint8Array(str.length);
str.split("").forEach((stri, i) => {
  arr[i] = stri.charCodeAt();
});
download(arr, "textUInt8Array.txt", "text/plain" );

// ### HTML
// html 字符串实例
download(document.documentElement.outerHTML, "dlHTML.html", "text/html");
// html Blob 实例
download(new Blob(["hello world".bold()]), "dlHtmlBlob.html", "text/html");
// ajax 回调实例
$.ajax({
    url: "/download.html",
    success: download.bind(true, "text/html", "dlAjaxCallback.html")
});

// ### 二进制文件
// 图片 URL
download("/diff6.png");
// 异步下载图片
const xhr = new XMLHttpRequest();
xhr.open("GET", "/diff6.png" , true);
xhr.responseType = "blob";
xhr.onload = (e) => {
    download(e.target.response, "awesomesauce.png", "image/png");
};
xhr.send();

7. 三方库 js-file-download

使用三方库 js-file-download 进行文件下载。与 downloadjs 一样,库小巧,无依赖,做了部分兼容。

下载 js-file-download
shell 复制代码
npm install js-file-download --save
使用方法

download(data, filename, mime, bom);

  • data:下载的数据内容,可以是 BlobFileStringdataURL
  • filename:要创建的文件的名称。
  • mime:要下载的文件的 MIME 内容类型,默认为 application/octet-stream
  • bom:向文件开头追加的内容。
示例
js 复制代码
// 简单使用
var fileDownload = require('js-file-download');
fileDownload(data, 'filename.csv');

// 二进制文件下载
import Axios from axios;
import fileDownload from 'js-file-download';

function download(url: string, filename: string) {
    Axios.get(url, {
        responseType: 'blob',
    }).then(res => {
        fileDownload(res.data, filename);
    });
}

8. 三方库 file-saver

使用三方库 file-saver 进行文件下载。该库兼容性比较好,基本兼容市面上所有浏览器。

常见浏览器兼容性表
Browser Constructs as Filenames Max Blob Size Dependencies
Firefox 20+ Blob Yes 800 MiB None
Firefox < 20 data: URI No n/a Blob.js
Chrome Blob Yes 2GB None
Chrome for Android Blob Yes RAM/5 None
Edge Blob Yes ? None
IE 10+ Blob Yes 600 MiB None
Opera 15+ Blob Yes 500 MiB None
Opera < 15 data: URI No n/a Blob.js
Safari 6.1+* Blob No ? None
Safari < 6 data: URI No n/a Blob.js
Safari 10.1+ Blob Yes n/a None
下载 file-saver
shell 复制代码
npm install jfile-saver --save
使用方法

saveAs(data, filename, options = { autoBom: true });

  • data:下载的数据内容,可以是 BlobFileUrl
  • filename:要创建的文件的名称。
  • { autoBom: true } :自动提供 Unicode 文本编码提示(参考:byte order mark)。
示例
js 复制代码
var FileSaver = require('file-saver');

// 将Blob保存为文本
var blob = new Blob(["Hello, world!"], {type: "text/plain;charset=utf-8"});
FileSaver.saveAs(blob, "hello world.txt");

// 从url下载文件
FileSaver.saveAs("https://httpbin.org/image", "image.jpg");

// 将canvas画布保存为文件
var canvas = document.getElementById("my-canvas");
canvas.toBlob(function(blob) {
    saveAs(blob, "pretty image.png");
});

// 将File保存为文件
// 注:IE 与 Edge 不支持 File 对象。
// 因此,使用 Blob 对象是更好的选择,saveAs(blob, filename)
var file = new File(["Hello, world!"], "hello world.txt", {type: "text/plain;charset=utf-8"});
FileSaver.saveAs(file);

下载篇后记

这里主要整理了一些前端常见的文件下载方法,以及一些三方库,算是相对比较丰富的整理文章。根据不同场景不同需求,可以使用合适的方法进行定制。

普通的下载方式已经能够满足大部分的开发需求,为什么还要整理三方库呢。一般来说,库提供的方法都比较简单易用,库的作者已经处理了很多问题,比如兼容性问题。同时,使用库的人越多,也越能保证库不会出现一些奇奇怪怪的问题。

参考文献或文章


上传篇

在整理上传前,首先要有的是如何获取文件。通常情况下,是使用最常用的 html 表单控件: input[type=file] 来获取文件。它允许用户打开系统的文件选择框,在选择文件后,能够加载并读取到所选择的相关文件及信息,多文件需要需要配置属性 multiple

html 复制代码
<input id="fileInput" type="file" accept="image/*" multiple onchange="selectFile()" />
  • type:申明 <input> 的输入类型,type="file" 表示表单控件的类型为文件选择。
  • accept:仅对 type="file" 输入类型有效。accept 属性定义了 file 上传控件可选择文件类型的列表。可参见 file 输入类型以了解更多信息。
  • multiple:可以通过 type="file" 输入选择多个文件。
js 复制代码
const fileInput = document.getElementById('fileInput');

function selectFile () {
  const file = fileInput.files[0];
}

1. form 表单

直接利用 form 表单提供的功能实现文件上传。使用简单,将其他操作都交由浏览器处理。

html 复制代码
<form action="https://example.com/files/upload" enctype="multipart/form-data" method="post">
  <input name="fileInput" type="file" />
  <button type="submit">提交</button>
</form>

2. FormData 对象

使用 FormData 对象,创造一个表单对象,再利用 ajax 等方式进行上传。

js 复制代码
const formData = new FormData()
formData.append('file', file, file.name)

const xhr = new XMLHttpRequest()
xhr.open('POST', 'https://example.com/files/upload', true)
xhr.send(formData)

参考文献或文章

相关推荐
游离状态的猫15 小时前
JavaScript性能优化实战:从瓶颈定位到极致提速
开发语言·javascript·性能优化
小彭努力中5 小时前
7.Three.js 中 CubeCamera详解与实战示例
开发语言·前端·javascript·vue.js·ecmascript
滿6 小时前
Vue3 Element Plus el-tabs数据刷新方法
javascript·vue.js·elementui
LinDaiuuj6 小时前
判断符号??,?. ,! ,!! ,|| ,&&,?: 意思以及举例
开发语言·前端·javascript
敲厉害的燕宝6 小时前
Pinia——Vue的Store状态管理库
前端·javascript·vue.js
Aphasia3116 小时前
react必备JavaScript知识点(二)——类
前端·javascript
珠峰下的沙砾6 小时前
Vue3 里 CSS 深度作用选择器 :global
前端·javascript·css
前端_学习之路7 小时前
javaScript--数据结构和算法
javascript·数据结构·算法
拉不动的猪7 小时前
# 移动端与PC端全屏的处理
前端·javascript·面试
excel7 小时前
招幕技术人员
前端·javascript·后端