前段時間聽到前端同學說前端拿到資源的CDN鏈接后可以直接從CDN下載資源,不需要經過后端,感覺很神奇,但是一直不明白是怎么實現的,前兩天整理了下關於
CDN和對象存儲的知識,今天搜了下前端直接下載資源的方式,特此記錄。
目前前端直接下載web服務器或者CDN靜態資源的方式有兩種,一個是利用<a>標簽,另一個是通過window.open()函數。
一、利用<a>標簽
<a>標簽就是html中的超鏈接標簽,但是用過這個標簽的同學應該都有這種印象,當超鏈接鏈接的內容是圖片、視頻或者pdf時,點擊超鏈接往往會在瀏覽器的新標簽頁打開對應的圖片、視頻或者pdf,而不會開始下載。但是其他像壓縮包這樣的資源,也就是瀏覽器沒辦法直接打開的資源則會直接開始下載。比如點擊
test_download.zip這個超鏈接,這個是一個zip包,所以會開始下載。那怎么樣讓所有的文件都默認下載而不是打開呢?
html5給<a>標簽增加了一個download屬性,當<a>標簽帶上了download屬性時,點擊超鏈接則會被瀏覽器解析為下載而不是打開。
下面我們來實操一下:
<a>標簽未添加download屬性
比如這個是不帶download屬性的<a>標簽案例。點擊
test_download.zip這個超鏈接可以下載對應的圖片和文件夾,只需要把博客里的代碼拷貝到文件夾里的index.html中就能看到效果。
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title></title> </head> <body> <img src = "img/books/book1.jpg" alt = "日俄海戰"/> <a href = "img/books/book1.jpg">點擊下載圖片</a> </body> </html>
用瀏覽器打開html文件后,點擊超鏈接

在新標簽頁中打開了圖片,並沒有下載。
<a>標簽添加download屬性后
給<a>標簽添加download屬性后,再試一次:
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title></title> </head> <body> <img src = "img/books/book1.jpg" alt = "日俄海戰"/> <a href = "img/books/book1.jpg" download="日俄海戰.jpg">點擊下載圖片</a> </body> </html>
用瀏覽器打開html文件后,點擊超鏈接,彈出了路徑選擇窗口,點擊確定,圖片完成下載。
換成網絡圖片再試一次
讓我們把<img>標簽和<a>標簽的路徑換成一張網絡圖片,而非本地圖片,
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <!--解決img標簽不能展示網絡圖片的問題--> <meta name="referrer" content="no-referrer"> <title></title> </head> <body> <img src = "https://img2020.cnblogs.com/blog/1456655/202110/1456655-20211004112059587-1817640282.png" alt = "cdn和對象存儲"/> <a href = "https://img2020.cnblogs.com/blog/1456655/202110/1456655-20211004112059587-1817640282.png" download="cdn和對象存儲.png">點擊下載圖片</a> </body> </html>
點擊下載的超鏈接,會發現並沒有開始下載,而是在新標簽頁打開了圖片。
注意:如果你的網絡圖片渲染不出來,嘗試在
<head>標簽內添加 <meta name="referrer" content="no-referrer">
沒有開始下載原因
如果加上download屬性,文件還是直接打開,無法正常下載,這有可能是download屬性失效造成的。
download屬性也受同源策略的影響,即非同一端口下不能直接下載第三方文件,所以這里download失效之后做的僅僅是跳轉功能:

解決方案
換個推流的方式,也就是用js將資源按照二進制流的方式讀取,對二進制流生成一個url,把url綁定到<a>標簽的href屬性中,因為瀏覽器無法打開二進制流文件,所以對於這樣的資源,瀏覽器將開始下載而不是在新標簽頁打開資源。
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <!--解決img標簽不能展示網絡圖片的問題--> <meta name="referrer" content="no-referrer"> <!--代替import axios from 'axios'語句--> <script src="https://unpkg.com/axios/dist/axios.min.js"></script> <title></title> </head> <script> // import axios from 'axios' /** * 下載文件 * @param url 文件url * @param fileName */ function downloadByURL(url,fileName) { axios .get(url, { responseType: 'blob' }) .then(response => { data = response.data if (!data) return const blob = new Blob([data], {type: "image/png"}) const link = document.createElement("a") // 創建<a>標簽 link.style.display = "none" // 隱藏<a>標簽 link.href = URL.createObjectURL(blob) // 根據二進制流對象生成一個url link.download = fileName // 這里填保存成的文件名 link.click() //強制觸發a標簽事件 URL.revokeObjectURL(link.href) link.remove(); }); } </script> <body> <img src = "https://img2020.cnblogs.com/blog/1456655/202110/1456655-20211004112059587-1817640282.png" alt = "cdn和對象存儲"/> <a href = "#" onclick="downloadByURL('https://img2020.cnblogs.com/blog/1456655/202110/1456655-20211004112059587-1817640282.png','cdn.png')">點擊下載圖片</a> </body> </html>
保存修改后,刷新瀏覽器,點擊下載超鏈接,可以看到再次彈出了路徑選擇的彈窗
打開本地文件,證實確實下載成功。
提示:
1、<head>標簽中的 <script src="https://unpkg.com/axios/dist/axios.min.js"></script>用於替換import axios from 'axios',因為我們在js中用到了axios,但是import語句貌似只能用在獨立的js文件中,不能像上面這樣嵌入在html里面。如果不像這樣替換,瀏覽器console會報錯import axios from 'axios'
2、在瀏覽器渲染html時,一直會提示下面這個跨域問題,這個問題暫時沒有徹底解決,但是可以通過
這個方法暫時屏蔽掉這個問題。
Access to XMLHttpRequest at 'https://img2020.cnblogs.com/blog/1456655/202110/1456655-20211004112059587-1817640282.png' from origin 'http://127.0.0.1:8020' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
這有一篇關於谷歌瀏覽器跨域問題的博客,以后回來看【譯】3種解決CORS錯誤的方式與Access-Control-Allow-Origin的作用原理
二、使用window.open()下載
樣例代碼如下,
我試了下,確實可以下載,但是打開下載下來的圖片卻提示文件格式錯誤,不知道為什么,如果下載一個本地的txt文件,則會把當前網頁的html源碼下載下來,很奇怪。搞不懂,以后有時間再來想。
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title></title> </head> <script> function downloadByURL(url){ window.open(url,'_self') } </script> <body> <img src = "img/books/book1.jpg" alt = "日俄海戰"/> <a href = "#" onclick="downloadByURL('img/books/book1.jpg')" download="日俄海戰.jpg">點擊下載圖片</a> </body> </html>
參考: