這種須要後端配置響應參數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
四、若是沒設置響應頭,又跨域,那隻能使用服務器代理