前端下載文件一般會遇到這樣兩種狀況html
下面如下載excel文件爲例,分別模擬展現這兩種狀況。(前置準備:vscode,node8+,vue-cli3.5+)。前端
1、 經過文件地址直接下載vue
在空目錄test下新建service目錄模擬後端,新建index.html文件模擬前端。node
在service目錄中新建一個excel文件 test.xlsx用於下載。ios
安裝serve用來啓動靜態資源服務器ajax
npm install -g serve
複製代碼
進入service目錄,啓動服務vue-cli
cd service
serve -s
複製代碼
此時這個test文件的地址就是:http://localhost:5000/test.xlsxnpm
在頁面中放一個a標籤,href中寫上文件的路徑,並寫上download屬性。axios
<a href="http://localhost:5000/test.xlsx" download>點擊下載</a>
複製代碼
在瀏覽器中打開index.html,點擊下載。後端
這種下載至關於一個get請求,瀏覽器直接訪問該靜態資源地址,download屬性告訴瀏覽器這個a標籤不是打開頁面預覽而是進行下載。
這與一般在實際項目中經過ajax請求接口無關,只須要照常請求,由於後端返回的只是文件的地址,拿到地址後綁定在a標籤中或者經過window.open()均可以進行下載,再也不單獨在項目中進行演示。
2、二進制流文件下載
這種狀況通常就是實際項目使用的ajax請求接口方式,好比post請求,前端傳遞若干參數,後端返回文件二進制流。
刪除index.html,返回test目錄下,使用vue-cli建立一個vue項目。
cd ../
vue create demo
複製代碼
選擇最簡單的default模板,建立好後進入項目目錄安裝axios,最後啓動。
cd demo
npm i axios --save
npm run serve
複製代碼
刪除src/App.vue中的多餘內容,添加一個下載按鈕。
<input type="button" value="點擊下載">
複製代碼
在service目錄中建立service.js寫一個下載的接口。
關於跨域cors設置參考:juejin.cn/post/684490…
const http = require("http");
const fs = require("fs");
// 建立服務
const server = http.createServer((req,res) => {
// 下載接口
if(req.url === "/download") {
res.writeHead(200, {
"Content-type": "application/vnd.ms-excel", // 返回excel文件
// 跨域設置
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Headers": "content-type"
})
// 異步讀取文件內容
fs.readFile("test.xlsx", (err, data) => {
// 返回二進制流文件
res.end(data)
})
}
})
// 服務啓動在3000端口
server.listen(3000)
console.log("server run at 3000")
複製代碼
在service目錄下新開一個終端窗口,啓動後端服務。
node service.js
複製代碼
回到App.vue,給下載按鈕添加點擊事件。
<input type="button" value="點擊下載" @click="handleDownload">
handleDownload() {
axios({
method: 'post',
url: "http://localhost:3000/download",
data: {
test: "test data"
}
}).then(response => {
console.log(response.data)
})
},
複製代碼
此時點擊下載,能夠看到返回的結果是亂碼。
其實根本原理跟上面普通下載同樣,都是經過一個文件的地址去下載,因此如今關鍵就是如今把這些二進制數據生成一個文件url。
首先設置axios配置項返回結果爲二進制格式。
axios({
method: 'post',
url: "http://localhost:3000/download",
data: {
test: "test data"
},
responseType: "arraybuffer" // arraybuffer是js中提供處理二進制的接口
})
複製代碼
拿到返回數據後,將二進制數據生成一個文件url,用URL.createObjectURL生成url時須要傳入Blob類型的參數。
關於Blob類型:juejin.cn/post/684490…
生成了url後就是模擬a標籤來下載。
.then(response => {
// 用返回二進制數據建立一個Blob實例
let blob = new Blob([response.data], {
type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
}) // for .xlsx files
// 經過URL.createObjectURL生成文件路徑
let url = window.URL.createObjectURL(blob)
// 建立a標籤
let ele = document.createElement("a")
ele.style.display = 'none'
// 設置href屬性爲文件路徑,download屬性能夠設置文件名稱
ele.href = url
ele.download = "測試文件"
// 將a標籤添加到頁面並模擬點擊
document.querySelectorAll("body")[0].appendChild(ele)
ele.click()
// 移除a標籤
ele.remove()
});
複製代碼
回到瀏覽器點擊下載,此次二進制流文件下載成功。
完