前言
常见文件下载与上传方式。持续整理更新中,欢迎各位反馈。
下载篇
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');
fetch
与 XMLHttpRequest
都能实现下载进度监听。fetch
下载方式的进度监听可以参考文章 fetch 下载文件 + 显示进度 ,感谢作者 BigLu 对此的整理。
- 优点:能够更加细致的控制下载过程。能够感知下载进度。
fetch
方法已经被各大浏览器厂商支持,适配度不错。适用于服务端动态生成文件的下载,服务的不需要对该文件副本进行保存,可以节约服务器资源。 - 缺点:相对前两种下载方式会比较复杂。下载过程中会用到
Blob
与URL.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:下载的数据内容,可以是
Blob
、File
、String
或dataURL
。 - 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:下载的数据内容,可以是
Blob
、File
、String
或dataURL
。 - 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:下载的数据内容,可以是
Blob
、File
或Url
。 - 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);
下载篇后记
这里主要整理了一些前端常见的文件下载方法,以及一些三方库,算是相对比较丰富的整理文章。根据不同场景不同需求,可以使用合适的方法进行定制。
普通的下载方式已经能够满足大部分的开发需求,为什么还要整理三方库呢。一般来说,库提供的方法都比较简单易用,库的作者已经处理了很多问题,比如兼容性问题。同时,使用库的人越多,也越能保证库不会出现一些奇奇怪怪的问题。
参考文献或文章
- MDN 手册:
Blob
- 作者 BigLu 整理文章: fetch 下载文件 + 显示进度
- 作者 饺子不放糖 整理文章: 前端文件下载的多种方法解析:从基础到高级
- 作者 唐诗 整理文章: 这两个前端下载库推荐给你
- 菜鸟教程: 使用 JS 的 download 库来下载资源
- github:
rndme/download
kennethjiang/js-file-download
eligrey/FileSaver
上传篇
在整理上传前,首先要有的是如何获取文件。通常情况下,是使用最常用的 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)