圖片下載的幾種實現
下載圖片的幾種方式
通過瀏覽器自動下載。瀏覽器接收到二進位制檔案,自動轉碼下載。比如:window.open()
通過xhr下載。ajax請求得到的是二進位制檔案,只能手動轉碼下載。
第一種:瀏覽器自動下載型
這種需要後端配置響應引數
window.open
例子:
本地起了一個node服務,埠3000
設定了content-disposition的情況:
頁面設定:
<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>
後端:
app.get('/img', (req, res) => {
res.setHeader('Content-Type', 'image/jpeg');
// res.download自動設定Content-disposition
res.download('./public/1.jpg');
})
實驗結果:
ie >=8 ,成功下載圖片;
chrome,成功下載圖片;
未設定content-disposition的情況
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');
}
實驗結果:
瀏覽器 | chrome | ie |
---|---|---|
同域 | 可以下載 | 不能下載 |
跨域 | 開啟新標籤頁 | 不能下載 |
設定content-disposition | 可以下載 | 不能下載 |
沒設定content-disposition | 可以下載 | 不能下載 |
所以a標籤下載跟瀏覽器的相容性和是否跨域有關
第一種情況結論
1、對於圖片下載,需要設定響應頭:`content-disposition`,該欄位的作用是告訴瀏覽器,這是一個附件;對於excel表格,不管是否設定了響應頭,都會下載。
2、window.open()沒有跨域問題,沒有瀏覽器相容性問題
3、相對於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
東莞vi設計https://www.houdianzi.com/dgvi/ 豌豆資源網站大全https://55wd.com
還有一種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)
})
最後
1、如果響應頭設定有content-disposition,可以使用window.open
2、不滿足1時,可以使用a標籤下載
3、如果要相容ie,可以使用navigator.msSaveBlob
4、如果沒設定響應頭,又跨域,那隻能使用伺服器代理