前端從web伺服器或者CDN下載資源
前段時間聽到前端同學說前端拿到資源的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 = "//img2020.cnblogs.com/blog/1456655/202110/1456655-20211004112059587-1817640282.png" alt = "cdn和對象存儲"/> <a href = "//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="//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 = "//img2020.cnblogs.com/blog/1456655/202110/1456655-20211004112059587-1817640282.png" alt = "cdn和對象存儲"/> <a href = "#" onclick="downloadByURL('//img2020.cnblogs.com/blog/1456655/202110/1456655-20211004112059587-1817640282.png','cdn.png')">點擊下載圖片</a> </body> </html>
保存修改後,刷新瀏覽器,點擊下載超鏈接,可以看到再次彈出了路徑選擇的彈窗
打開本地文件,證實確實下載成功。
提示:
1、<head>標籤中的 <script src=”//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 '//img2020.cnblogs.com/blog/1456655/202110/1456655-20211004112059587-1817640282.png' from origin '//127.0.0.1:8020' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
使用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>
參考: