图片下载的几种实现

下载图片的几种方式

  • 经过浏览器自动下载。浏览器接收到二进制文件,自动转码下载。好比:window.open()
  • 经过xhr下载。ajax请求获得的是二进制文件,只能手动转码下载。

第一种:浏览器自动下载型

这种须要后端配置响应参数javascript

window.open

例子:
本地起了一个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

    • ie >=8 ,成功下载图片;
    • chrome,成功下载图片;
  • 未设置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);
    })

    实验结果:后端

    • 图片在新标签页打开
    • excel表自动下载了
经过a标签请求
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转换
经过xhr转换的有多种
blob下载

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);
    })
}

实验结果:

  • blob下载,使用的是Blob构造函数。最后仍是要建立a标签下载。咱们也知道a标签下载的一些缺点,一样blob下载也存在这样的缺点。
  • getResponseHeader,若是是跨域,只能获取到Cache-Control,Content-Language,Content-Type,Expires,Last-Modified,Pragma几个响应头,若是须要获取其余的响应头,须要设置Access-Control-Expose-Headers
兼容ie下载文件

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();

    实验结果:

    • 兼容性:ie,chrome
    • 可是要设置content-disposition
  • 还有一种ie自有的下载文件,ie10以上
window.navigator.msSaveBlob(blob, '1.jpg');
跨域,没设置响应头,又要兼容ie

这种状况只能说是做死,可是没办法,实际状况也有可能有这么样。这种状况呢,只能是使用服务端作代理。这里使用的是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

四、若是没设置响应头,又跨域,那只能使用服务器代理

相关文章
相关标签/搜索