今天工作碰到一個需求,點擊按鈕導出excel,后端是直接返回的文件流,如下圖:
方案一
直接用a標簽來改造這個按鈕,把下載地址放到href里,因為后端已經在響應頭里設置了文件名和文件類型,點擊按鈕就能下載帶有默認文件名的excel文件了。但是這個方案中,地址如果是動態的就不夠靈活了。
方案二
按鈕不變成a標簽,在按鈕的點擊事件里處理
// 獲取baseurl
click(){
const baseurl= `xxx`;
// 拼接上導出的地址,如果接口還需要其他參數,都可以直接拼接上
let url=`${baseurl}/xxx/export/${xxx}`
// 第二個參數'_self'表示在當前頁下載,不打開新的頁面
window.open(url,'_self')
}
方案三
直接處理文件流
axios({
method: '請求方法(get/post)',
url: '地址',
data: '請求參數',
responseType: 'blob' // 響應數據的類型要設置成blob,設置arraybuffer也可以,下文有解釋
}).then((res) => {
// 解析文件名
const str = res.headers['content-disposition'].split(';')[1].split('=')[1];
const filename = decodeURIComponent(str);
// 用blob存儲二進制文件
const blob = new Blob([res.data], {
type: 'application/vnd.ms-excel', // 設置文件類型 pdf是application/pdf,word是application/vnd.openxmlformats-officedocument.wordprocessingml.document,其他類型可以百度一下
});
// 創建一個臨時的url指向blob對象
const objectUrl = window.URL.createObjectURL(blob);
// 創建url之后可以模擬對此文件對象的一系列操作,例如:預覽、下載
const a = document.createElement('a');
a.setAttribute('href', objectUrl);
a.setAttribute('download', filename);
a.click();
// 5.釋放這個臨時的對象url
window.URL.revokeObjectURL(objectUrl);
}).catch(error => {
...
});
Blob(Binary Large Object)是用于表示大型二進制數據對象的 JavaScript 數據類型。它是一個不可變的原始數據對象,可以存儲各種類型的數據,如圖像、音頻、視頻和其他任意二進制數據。
Blob 對象和 ArrayBuffer 對象在某些方面相似,因為它們都可以用來存儲二進制數據。但是,它們之間也存在一些重要的區別。
數據存儲形式:ArrayBuffer 是一個連續的、固定長度的原始二進制數據緩沖區。它是在內存中分配一塊指定長度的空間來存儲數據。而 Blob 是一個非連續的二進制數據對象,它可以由多個片段(即 Blob 的數據塊)組成。這意味著 Blob 對象可以由不同的數據來源進行構建,例如從文件、網絡請求或其他 Blob 對象中創建。
可訪問性:ArrayBuffer 對象提供了一種機制,通過 TypedArray 和 DataView 視圖來直接讀取和修改數據。而 Blob 對象并不直接暴露數據的內容,而是提供了一組異步方法(例如 FileReader)來讀取其中的數據。
用途和應用場景:ArrayBuffer 主要用于在 JavaScript 中高效地處理和操作二進制數據,例如圖像處理、音頻解碼、加密算法等。而 Blob 對象更適合用于處理文件、上傳下載、數據傳輸等場景,因為它可以方便地保存和傳遞整個數據塊,而不需要直接讀取或修改其內容。
總結一下,ArrayBuffer 和 Blob 都是用于處理二進制數據的 JavaScript 數據類型。ArrayBuffer 是一個連續的固定長度二進制數據緩沖區,而 Blob 是一個非連續的二進制數據對象,可以由多個片段組成。ArrayBuffer 提供了直接讀取和修改數據的能力,而 Blob 則適用于處理文件、上傳下載和數據傳輸等場景。根據具體的使用需求,選擇使用適合的數據類型來操作和處理二進制數據。
補充
最近開發時,和新的后端同學聯調時發現要么下載的文件打不開,要么下載的文件是空白,研究了一下發現是后端代碼少配置了幾個屬性,Access-Control-Expose-Headers
這個響應頭的屬性需要設置前端可見,Content-Type
要設置成對應的文件類型,Content-Disposition
數據處理方式和文件名也要處理一下。
下面代碼是我用koa寫的后端獲取文件流示例代碼,安裝koa和koa2-cors的依賴后,把需要給前端的文件地址配置一下,就可以node index.js運行了,給前端的url就是http://localhost:3000。
文件名:index.js
const Koa = require('koa');
const cors = require('koa2-cors');
const fs = require('fs');
const path = require('path');
const app = new Koa();
app.use(cors());
// 讓Content-Disposition在前端可見,需要設置Access-Control-Expose-Headers
app.use(async (ctx, next) => {
ctx.set('Access-Control-Expose-Headers', 'Content-Disposition');
await next();
});
app.use(async ctx => {
// 獲取文件路徑
const filePath = path.join(__dirname, './jianli.pdf'); // 你的文件地址
// 讀取文件
const file = fs.readFileSync(filePath);
// 設置響應類型為pdf
ctx.set('Content-Type', 'application/pdf');
// 設置響應頭,使其可以下載,你可以設置你想要的文件名
ctx.set('Content-Disposition', 'attachment; filename=jianli.pdf');
// 將文件內容賦值給response.body
ctx.body = file;
});
app.listen(3000, () => {
console.log('Server is running at http://localhost:3000');
});