很多專案中都有下載一些圖片檔案的需求,常用的方式是通過a標籤實現:
<a href="download.jpg"></a>
複製程式碼
但是你會在使用時發現點選該連結後並不是下載對應的圖片,而是在瀏覽器中開啟了對應的圖片,這並不是我們想要的。
應為瀏覽器判斷是否下載一般會根據檔案返回的頭資訊進行判斷,如果給返回了對應的頭資訊則會進行下載:
header('Content-type: image/jpeg');
header("Content-Disposition: attachment; filename='download.jpg'");
複製程式碼
很好,但是如果這樣還需要後端人員的配合,我們有沒有其他的方式呢?有,那就是使用download
屬性:
<a href="download.jpg" download>下載</a>
複製程式碼
這樣就可以直接呼叫瀏覽器的下載功能,而且還可以通過傳參給download
來實現檔案的重新命名功能:
<a href="download.jpg" download="othername.jpg">下載</a>
複製程式碼
download
屬性的相容性如下:
但是這個方案依然有他的問題:
chrome 69.0.3497.92 中已經嚴格遵循同源策略的限制,如果載入了非同源的內容,download 屬性將失效,等效導航功能。
現在很多專案已經是前後端分離,經常遇到跨域的問題,但是在跨域的情況下download
屬性完全沒有作用,那麼應該如何解決。
基本的思路就是讓跨域變成不是跨域。
一種思路就是通過反向代理進行處理,來解決跨域問題:
1.將原先訪問圖片雲服務的資源改為訪問網站圖片資源,例如:
<a href="http://prod.upaiyun.com/images/xxx.jpg" download="xxx.jpg">download</a>
改為:
<a href="http://www.mysite.com/images/xxx.jpg" download="xxx.jpg">download</a>
複製程式碼
2.配置nginx反向代理
location /images {
proxy_redirect off;
proxy_pass https://prod.upaiyun.com;
}
複製程式碼
另一種方式就是,建立一個非跨域的資料來源:
1.下載原資料檔案,這裡可以使用img標籤或者通過ajax,fetch進行下載
function download(url, name) {
name = name || url
// fetch抓取圖片資料
fetch(url).then(response=> {
if( response.status == 200 )
// 返回的.blob()為promise,然後生成了blob物件,此方法獲得的blob物件包含了資料型別,十分方便
return response.blob()
throw new Error(`status: ${response.status}.`)
}).then(blob=> {
// 獲取到blob物件
downloadFile(name, blob)
}).catch(error=> {
console.log("failed. cause:", error)
})
}
複製程式碼
2.通過URL.createObjectURL
給a標籤設定資料來源
function downloadFile(fileName, blob) {
const anchor = document.getElementById("a")
// 建立指向blob物件地址
const src = URL.createObjectURL(blob)
anchor.download = fileName
anchor.href = src
}
複製程式碼
這樣就可以實現在跨域情況下的圖片資源的下載。
當然還有一下其他類似的方案如使用FileReader
的readAsDataURL
來生成資料,或使用Canvas
的toDataUrl
都可以達到一樣的效果。