傳送 物件/陣列 到 FORMDATA
Mesak
Posted on May 8, 2022
JS 自從有了打包工具之後,很多工具造福不少開發者,以往要送個 AJAX 到後端,大多都是一個頁面處理一個 method
框架化後,每個程式碼開始有了 物件化、封裝方式來做,現在大多都用 axios 來送 AJAX
但是遇到一個問題就是送檔案的時候,需要使用到 FormData 的物類別物件。
但是整個像後端送的程式碼都封裝起來了,要針對一個檔案上傳的方法,做出額外處理,當檔案上傳處理頁面多了之後維護除錯方法就有點麻煩。
所以比較好的方式還是修改 API 送出前,先把物件轉換好判定是否有 File
類型,然後轉換成 FormData
就可以一勞永逸
問題來了,以往直接用 axios 傳送到後端,一個 object 就可以搞定 value is array 的問題,開發者似乎不用煩惱太多後續處理問題
頂多就是遇到 GET
網址參數需要轉換純文字的狀態,但也也只需要一個 qs 套件就可以解決解決
但如果採用 FormData
這個類型的時候,整個 object 就必須自己處理,如果遇到傳送一個陣列的時候,就必須額外針對 key = array 的狀態去處理,然後如果 value = array 也是很麻煩的事情。
舉個例子,往後端送 array1 = [1,2,3]
,如果是 axios 就可以直接送,如果是送 FormData 就必須處理成
array1[]:1;
array1[]:2;
array1[]:3;
這點可以利用 PostMan 來做測試看看後端可以吃到怎樣結構的陣列
這邊原本的想法是,把物件的每個 value 歷遍,只要 value instanceof File
就成立條件,把 key 轉換成陣列
不過找了很多遞迴解法,都沒有 qs 轉換 陣列來的快速有效,最終還是爬了一下 qs 的實際操作用法,
const files = new Map()
const queryString = qs.stringify(data, {
arrayFormat: 'brackets',
encode: false,
filter: (name, value) => {
if (value instanceof File) {
let id = lodash.uniqueId('__FILE__.')
files.set(id, value)
return id
} else {
return value
}
}
})
利用 qs 的 filter method 把所有 value 檔案移到暫存變數 files 裡面,利用 lodash 取得目前唯一的數值,將原先的 data (object) 的 File 類型 value,全部轉換成 file 的 uniqueId,最終就可以得到一串處理過的字串,快速的將 物件陣列轉換成字串
a=__FILE__.1&b[a]=1&b[b]=2 ...
只要有了這個純字串的東西,要拆解成陣列 + 物件就方便多拉,拆完之後遇到 FILE 的 value 記得去把 files 裡面的檔案給領回來,這樣塞入 FormData
就可以解決陣列 key 或是 value = array 的問題了
完整範例放在 codepen.io
Posted on May 8, 2022
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.