这种须要后端配置响应参数javascript
例子:
本地起了一个node服务,端口3000html
设置了content-disposition的状况:java
页面设置:node
<button onclick="downImg(1)">点击下载图片</button> <button onclick="downImg(2)">点击下载excel</button> <script> function downImg(type) { if(type ===1) { window.open('http://127.0.0.1:3000/img'); } else { window.open('http://127.0.0.1:3000/api'); } } </script>
后端:es6
app.get('/img', (req, res) => { res.setHeader('Content-Type', 'image/jpeg'); // res.download自动设置Content-disposition res.download('./public/1.jpg'); })
实验结果:ajax
未设置content-disposition的状况chrome
app.get('/img', (req, res) => { res.setHeader('Content-Type', 'image/jpeg'); let pathname = path.join(__dirname, './public/1.jpg') res.sendFile(pathname); })
app.get('/api', (req, res) => { res.setHeader('Content-Type', 'application/vnd.ms-excel'); let pathname = path.join(__dirname, './public/api.xlsx') res.sendFile(pathname); })
实验结果:后端
function alabel(src, downloadName) { // 注意,ie11还不支持es6的语法 var a = document.createElement('a'); a.target = "_blank"; a.href = src; a.download = downloadName; a.click(); } function downImg() { var url = 'http://127.0.0.1:3000/img'; alabel(url, '1.jpg'); }
实验结果:api
浏览器 | chrome | ie |
---|---|---|
同域 | 能够下载 | 不能下载 |
跨域 | 打开新标签页 | 不能下载 |
设置content-disposition | 能够下载 | 不能下载 |
没设置content-disposition | 能够下载 | 不能下载 |
因此a标签下载跟浏览器的兼容性和是否跨域有关跨域
一、对于图片下载,须要设置响应头:`content-disposition`,该字段的做用是告诉浏览器,这是一个附件;对于excel表格,无论是否设置了响应头,都会下载。 二、window.open()没有跨域问题,没有浏览器兼容性问题 三、相对于a标签,window.open会好一些,a标签有浏览器的兼容性问题。
经过xhr转换的有多种
blob下载必须设置responseType:blob
,不然返回的是一堆乱码的字符串。设置responseType:blob
以后,浏览器将返回数据转成blob
对象。
首先,建立xhr对象,请求接口
接下来是常见的浏览器网络请求接口4步骤:
createXHR(url, data, method, successCallBack, errCallBack) { // 建立xhr对象 let xhr = new XMLHttpRequest(); // 链接 xhr.open(method, url); // 发送 xhr.send(data); // 必须设置responseType,不然返回的是字符串 xhr.responseType = "blob"; xhr.onreadystatechange = function() { // xhr的请求状态有0,1,2,3,4 if(xhr.readyState === 4) { // 返回的状态码 if(xhr.status === 200) { // Content-Disposition获取文件名 successCallBack(xhr.response, xhr.getResponseHeader("Content-Disposition")); } else { errCallBack(xhr.response); } } } }
调用createXHR
var url = 'http://127.0.0.1:3000/img'; createXHR(url, {},'GET', function(res, header) { let downloadName = header.split('filename="')[1].slice(0, -1); blob([res], 'image/jpeg', downloadName) }, function(e) { console.log(e); })
blob方法
blob(data, content_type, downloadName) { let blob = new Blob(data, { type: content_type}); // URL.createObjectURL生成一个DOMString, 包含了一个url对象,这个url对象与file对象或者blob对象有一个映射关系。 URL 的生命周期和建立它的窗口中的 document 绑定 let url = URL.createObjectURL(blob); alabel(url, downloadName); // 销毁url, 回收内存 URL.revokeObjectURL(url); }
能够使用blob构造函数,那也能够使用h5的fileReader, 由于fileReader继承blob。fileReader的写法以下:
// FileReader转换对象不须要数组形式,blob是数组格式 fileReader(res, '1.jpg'); fileReader(data, downloadName) { let reader = new FileReader(); reader.readAsDataURL(data); reader.addEventListener('load', function() { alabel(this.result, downloadName); }) }
实验结果:
Cache-Control,Content-Language,Content-Type,Expires,Last-Modified,Pragma
几个响应头,若是须要获取其余的响应头,须要设置Access-Control-Expose-Headers
a标签下载有浏览器兼容问题。要兼容ie就要找其余的方法。前面有提到的window.open,还有一种是iframe
iframe标签
var url = 'http://127.0.0.1:3000/img'; var iframe = document.createElement("iframe"); iframe.src = url; iframe.style.display = "none"; document.body.appendChild(iframe); iframe.click();
实验结果:
window.navigator.msSaveBlob(blob, '1.jpg');
这种状况只能说是做死,可是没办法,实际状况也有可能有这么样。这种状况呢,只能是使用服务端作代理。这里使用的是node作代理。
页面:
// url是目标图片地址, serverApi是本地服务器接口 var url = 'http://http://127.0.0.1:3001/img'; var serverApi = 'http://127.0.0.1:3000/download' createXHR(serverApi, {url},'POST', function(res, header) { blob(res, 'image/jpeg','1.jpg'); }, function(e) {/* */ console.log(e); })
服务端:
app.post('/download', (req, res) => { res.setHeader('Content-Type', 'image/png') request.get(req.body.url).pipe(res) })
一、若是响应头设置有content-disposition
,能够使用window.open
二、不知足1时,能够使用a标签下载
三、若是要兼容ie,能够使用navigator.msSaveBlob
四、若是没设置响应头,又跨域,那只能使用服务器代理