在 Vue 2.5 使用 Axios 處理檔案下載

做法

修改 plugins 資料夾的 axios.js 檔,設置一個回應攔截器,用於處理當請求失敗時,被轉換為 Blob 物件的 JSON 回應:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
import Vue from 'vue';
import axios from 'axios';
import VueAxios from 'vue-axios';

Vue.use(VueAxios, axios);

axios.defaults.baseURL = process.env.VUE_APP_API_URL;
axios.defaults.params = {};
// 回應攔截器
axios.interceptors.response.use(
response => response,
(error) => {
// 判斷回應類型是否為 Blob 物件
if (
error.request.responseType === 'blob'
&& error.response.data instanceof Blob
&& error.response.data.type
&& error.response.data.type.toLowerCase().indexOf('json') !== -1
) {
return new Promise((resolve, reject) => {
// 建立一個 FileReader 物件
const reader = new FileReader();
// 讀取完成時觸發
reader.onload = () => {
// 將資料內容寫入 error 的 data 中
error.response.data = JSON.parse(reader.result);
resolve(Promise.reject(error));
};
// 讀取失敗時觸發
reader.onerror = () => {
reject(error);
};
// 讀取指定的 Blob 物件
reader.readAsText(error.response.data);
});
}
return Promise.reject(error);
},
);

export default axios;

helpers 資料夾新增一個 file.js 檔:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
const file = {
download(data, fileName) {
// 建立一個指向 Blob 物件的 URL
const url = window.URL.createObjectURL(new Blob([data]));
// 建立一個用於下載的超連結
const link = document.createElement('a');
link.setAttribute('href', url);
link.setAttribute('download', fileName);
// 掛載超連結
document.body.appendChild(link);
// 下載
link.click();
// 移除超連結
document.body.removeChild(link);
// 釋放指向 Blob 物件的 URL
window.URL.revokeObjectURL(url);
},
};

export default file;

建立一個 axios 請求,並將回應類型設置為 Blob 物件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
return new Promise((resolve, reject) => {
axios({
method: 'GET',
url: '/bookings/export',
responseType: 'blob', // 設置回應類型
})
.then(({ data }) => {
file.download(data, 'bookings.xlsx'); // 下載
resolve();
})
.catch((error) => {
reject(error);
});
});