近来在做一个
文件下载
的功用,这里把做的历程顶用的手艺和坑扼要总结下。
1. 单文件下载(a标签)
同源单文件
针对单文件的情况下,同源的文件,能够经由过程 < a> 标签的 download 属性下载文件
const elt = document.createElement('a');
elt.setAttribute('href', url);
elt.setAttribute('download', 'file.png');
elt.style.display = 'none';
document.body.appendChild(elt);
elt.click();
document.body.removeChild(elt);
然则这个计划并不适用于非同源
的资本,此时它相当于平常的超链接,点击会跳转到资本页面,而不是下载。
非同源图片
假如不存在CORS题目, 能够借助Blob
完成下载(组织xhr请求文件地点, 以Blob的情势吸收Response):
function downloadWithBlob(url) {
fetch(url).then(res => res.blob().then(blob => {
var a = document.createElement('a');
var url = window.URL.createObjectURL(blob);
var filename = 'file.png';
a.href = url;
a.download = filename;
a.click();
window.URL.revokeObjectURL(url);
}));
}
假如存在CORS题目,能够斟酌运用 canvas
将图片转换成 base64
编码以后再经由过程 标签的 download 属性下载
function downloadPic(url) {
const img = new Image;
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
img.onload = function() {
canvas.width = this.width;
canvas.height = this.height;
ctx.drawImage(this, 0, 0);
const elt = document.createElement('a');
elt.setAttribute('href', canvas.toDataURL('image/png'));
elt.setAttribute('download', 'file.png');
elt.style.display = 'none';
document.body.appendChild(elt);
elt.click();
document.body.removeChild(elt);
};
img.crossOrigin = 'anonymous';
img.src = url;
}
2. 单文件下载(iframe)
iframe
体式格局是在页面内隐蔽iframe, 然后将下载地点加载到iframe中, 从而触发浏览器的下载行动
const iframe = document.createElement('iframe');
iframe.src = url;
iframe.style.display = 'none';
document.body.appendChild(iframe);
然则这里发明,即使是同域的图片,也没法完成下载,这是为啥呢?
这里就有个上面的a链接下载没有提到的题目:什么样的链接才触发浏览器的下载
:
url怎样触发浏览器自动下载
一个url可否触发浏览器自动下载,主要看该请求响应头response header
是不是满足,平常是看Content-Disposition
和Content-Type
这两个音讯头:
- response header中指定了
Content-Disposition为attachment
,它示意让浏览器把音讯体以附件的情势下载并保存到当地 (平常还会指定filename, 下载的文件名默许就是filename) - response header中指定了
Content-Type 为 application/octet-stream
(无范例) 或application/zip
(zip包时)等等。(个中 application/octet-stream示意http response为二进制流(没指定明白的type), 用在未知的应用程序文件,浏览器平常不会自动实行或讯问实行。浏览器会像看待 设置了HTTP头Content-Disposition 值为 attachment 的文件一样来看待这类文件)
只需url满足上述触发的请求,那末都能够经由过程iframe的情势来下载
3. 代办效劳处置惩罚下载
假如后端本身也能掌握的话,或许后端能合营的话,能够写一个代办效劳,在后端去请求文件数据,然后设置好响应的response header, 然后前端请求代办效劳来做下载。
前端(假定代办效劳接口是http://exampale.com/download):
const downloadUrl = 'http://exampale.com/download?url=' + encodeURIComponent(url) + '&name=xxx';
const elt = document.createElement('a');
elt.setAttribute('href', downloadUrl);
elt.setAttribute('download', 'file.png');
...
后端
const url = decodeURIComponent(req.query.url);
http.get(url, (response) => {
res.setHeader('Content-disposition', 'attachment;filename=' + req.query.name);
res.setHeader('Content-type', 'application/octet-stream');
response.pipe(res);
});
单文件的处置惩罚先写到这里,多文件的下载下篇在写。