概要 在前端下載文件是個很通用的需求,一般後端會提供下載的方式有兩種: 直接返迴文件的網路地址(一般用在靜態文件上,比如圖片以及各種音視頻資源等) 返迴文件流(一般用在動態文件上,比如根據前端選擇,導出不同的統計結果 excel 等) 第一種方式比較簡單,但是使用場景有限。第二種方式通用性更好,最近 ...
概要
在前端下載文件是個很通用的需求,一般後端會提供下載的方式有兩種:
- 直接返迴文件的網路地址(一般用在靜態文件上,比如圖片以及各種音視頻資源等)
- 返迴文件流(一般用在動態文件上,比如根據前端選擇,導出不同的統計結果 excel 等)
第一種方式比較簡單,但是使用場景有限。
第二種方式通用性更好,最近再使用 antd 開發的過程中,下載文件部分折騰了一下午,於是將關鍵的部分和遇到的一些問題整理如下。
前端核心代碼
我的前端是基於 antd pro 開發的,這裡不在詳細介紹 antd pro 相關的內容,只說明下封裝的下載函數:
import { request } from "umi";
// 這是我在項目中封裝的下載函數,有2個參數:
// 一個是文件的id,用來給後端API搜索文件用的
// 一個是文件名filename,這個給前端用的,下載時,預設保存的文件名
export async function DownloadFile(id: string, filename: string) {
return RestGet<BlobPart>(`/api/v1/file/download/${id}`, "blob").then(
(res) => {
let url = URL.createObjectURL(new Blob([res], { type: "octet/stream" }));
let a = document.createElement("a");
a.href = url;
a.download = filename;
a.click();
URL.revokeObjectURL(url);
}
);
}
// GET 方式請求後端API
export async function RestGet<T>(
url: string,
responseType: "json" | "blob" = "json"
) {
return request<T>(url, {
method: "GET",
headers: {
"Content-Type": "application/json",
},
responseType: responseType,
});
}
// POST 方式請求後端API
export async function RestPost<T>(
url: string,
body: any,
responseType: "json" | "blob" = "json"
) {
return request<T>(url, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
data: body,
responseType: responseType,
});
}
這個下載函數本質就是創建一個 <a>
元素,然後模擬點擊此 <a>
元素來完成下載。
對於 DownloadFile
函數,我是根據自己的需要封裝的,不一定非得是這兩個參數,可以根據自己的後端 API 來定製需要傳入的參數。
將下載封裝成函數之後看,前端就可以通過一個按鈕來下載文件了,比如:
<Button
type="link"
key="download"
icon={<DownloadOutlined />}
onClick={() =>
DownloadFile(item.video_file_id as string, (item.name as string) + ".mp4")
}
>
下載
</Button>
我這裡是 GET 方式下載文件的,如果參數比較多且複雜的話,也可以使用 POST 方式。
只要把 DownloadFile
中 RestGet<T>
改成 RestPost<T>
,並調整相應的參數即可。
遇到的問題
調試其中的下載方式就不提了,遇到的最大困難,搜索半天也沒什麼人提到的就是請求中的 responseType
問題。
剛開始,我沒有設置 responseType
,預設值好像是 json
或者 text
。
測試時發現,下載文本類型的文件沒有問題,但是下載二進位文件的話,比如視頻或者圖片,下載之後總是無法正常打開,前後端也沒有任何錯誤提示。
折騰了半天,才試出 responseType
傳入 blob
的話,二進位文件才能正常下載。
而且發現,設置成 blob
的話,文本類型的文件也能正常下載打開。