Fetch Request
web 環(huán)境下 Request Body 支持的 參數(shù) 類型有: String
, URLSearchParams
, Blob/File
, FormData
, ArrayBuffer
, ArrayBufferView
不同之處:
① RN 自身本僅支持 XMLHttpRequest
進(jìn)行網(wǎng)絡(luò)請求,支持的 Request Body 可通過 源碼1 > 源碼2 > 源碼3 查看,缺少了對 URLSearchParams
的支持南捂。
② RN Fetch 使用 whatwg-fetch
,通過 XMLHttpRequest
實(shí)現(xiàn)了 Fetch
功能继蜡,根據(jù) 源碼1 和 源碼2 可以看出 whatwg-fetch
支持 URLSearchParams
類型的 Request Body ,但在 RN 中少了臨門一腳逛腿。
String
body 為 String
稀并,請求格式如下
fetch
content-type: text/plain;charset=UTF-8
---------------------------
string
URLSearchParams
body 為 URLSearchParams
,請求格式如下
fetch
content-type: application/x-www-form-urlencoded;charset=UTF-8
---------------------------
String(URLSearchParams): foo=foo&bar=bar
不同之處:根據(jù) web 示例单默,支持 new URLSearchParams("foo=foo&bar=bar")
碘举,但根據(jù) RN 源碼,僅支持 new URLSearchParams({foo:"foo", bar:"bar"})
形式搁廓,且沒有實(shí)現(xiàn) get引颈、has、set 等方法境蜕。
Blob/File
body 為 Blob
蝙场,請求格式如下
fetch
content-type: Blob.type
---------------------------
String(Blob)
不同之處:根據(jù) Blob 文檔 和 RN 源碼
① 可以看到 RN Blob
未實(shí)現(xiàn) arrayBuffer
、stream
粱年、text
方法售滤。
② 創(chuàng)建 Blob
對象 new Blob(array, options)
中的 array
參數(shù),RN 只能使用 String
和 Blob
逼泣,而不能使用 ArrayBuffer
趴泌、ArrayBufferView
關(guān)于 RN Blob
(File 是繼承 Blob
實(shí)現(xiàn)的,二者基本一致拉庶,不再累述):
在瀏覽器中嗜憔,Blob
對象的數(shù)據(jù)緩存在瀏覽器中并與變量指針綁定。在 RN 中氏仗,Blob
對象的數(shù)據(jù)將緩存在原生端(其實(shí)也就是 app 運(yùn)行內(nèi)存中)吉捶,并生成一個唯一的 id,返回給 js 端皆尔,也就是說在 js 端存儲的僅是一個 id呐舔。后續(xù)則可通過 FileReader 與原生端交互,讀取 Blob
對象的實(shí)際數(shù)據(jù)慷蠕。Fetch
函數(shù)內(nèi)部已實(shí)現(xiàn)了數(shù)據(jù)讀取珊拼,可將 Blob
直接設(shè)置為 Request Body
。
Blob
的創(chuàng)建方式:
① 通過函數(shù)流炕,比如 Fetch
/ XMLHttpRequest
請求可以獲取到 Response Blob澎现,網(wǎng)絡(luò)請求是在原生端完成的,完成后原生端緩存響應(yīng)結(jié)果每辟,返回唯一 id 給 js 端創(chuàng)建 Blob剑辫。
② 也可以使用如下方法直接創(chuàng)建,js 會先將創(chuàng)建數(shù)據(jù)傳遞給原生端緩存渠欺,然后使用原生端返回的唯一 id 創(chuàng)建 Blob
const body = new Blob(
['<a id="a"><b id="b">hey!</b></a>'],
{type : 'text/html', lastModified:Date.now()}
);
-> 創(chuàng)建 -> string 傳到原生端 -> 返回 id -> js{id:....,type,}
const stream = new Blob(
[body, 'string'],
{type : 'text/html', lastModified:Date.now()}
);
-> 傳遞參數(shù) body 的 id 和 string -> 返回新 id -> js{id:...,type,}
FormData
body 為 Blob
妹蔽,請求格式如下 (以上 body
格式的 header content-type
由 whatwg-fetch
實(shí)現(xiàn),以下 header content-type
則在原生的 Android 端挠将、iOS 端 實(shí)現(xiàn) )
fetch
content-type: multipart/form-data; boundary=...
---------------------------
String(FormData)
不同之處:根據(jù) FormData 文檔 和 RN 源碼胳岂,可以看到有以下不同
① RN 僅實(shí)現(xiàn)了 append
、getParts
方法捐名,而沒有實(shí)現(xiàn) get
旦万、has
、set
等方法镶蹋。如果在 RN 中需要對已添加的 form data 進(jìn)行修改成艘,可通過 FormData._parts
進(jìn)行操作,但這種方法并不安全贺归,后續(xù) RN 可能會對 _parts
更新淆两,造成兼容性問題。
② append 方法與瀏覽器端的實(shí)現(xiàn)不同
// 瀏覽器, value 支持 String / File / Blob
var formData = new FormData();
formData.append('username', 'Chris');
formData.append('userpic', myFileInput.files[0], 'chris.jpg');
formData.append('blob', new Blob(
['<a id="a"><b id="b">hey!</b></a>'],
{type : 'text/html', lastModified:Date.now()}
));
// RN, value 支持 String / FIle
var formData = new FormData();
formData.append('username', 'Chris');
formData.append('userpic', {
uri: String,
type: 'image/jpeg',
name: 'photo.jpg',
});
關(guān)于 RN FormData
的幾點(diǎn)說明
- 查看 iOS源碼 和 Android 源碼拂酣,可以看出在原生端 RN 并未支持 FormData 添加 Blob 類型數(shù)據(jù)秋冰。
- RN 給了另外一種上傳文件的方式,通過
{uri, ...}
指定文件地址婶熬,uri
支持file://
,content://
(Android), 甚至還支持http://
網(wǎng)絡(luò)圖片 - 如果必須要求
FormData
支持Blob
對象剑勾,有兩種拓展思路(需自行實(shí)現(xiàn))- 先將
Blob
對象保存為臨時文件埃撵,然后通過{uri, ...}
添加,待請求完成后刪除臨時文件虽另,這種方式會產(chǎn)生臨時文件暂刘,且本來Blob
對象已在內(nèi)存中,保存為文件捂刺,發(fā)送請求谣拣,原生端會再次讀取臨時文件到內(nèi)存中,有點(diǎn)浪費(fèi)族展。 - Request body 支持
Blob
對象森缠,可根據(jù) 規(guī)則 自行將formData
轉(zhuǎn)換為multipart/form-data
類型的Blob
數(shù)據(jù),如果formData
中包含{uri, ...}
類型文件仪缸,則需要將該類型轉(zhuǎn)為Blob
對象才能與formData
中的其他String
贵涵、Blob
對象整合為一個統(tǒng)一的Blob
對象,實(shí)現(xiàn)起來略微麻煩點(diǎn)恰画。 - 所以独悴,如果可以調(diào)整思路避開使用
FormData Blob
,就盡量避開吧
- 先將
ArrayBuffer / ArrayBufferView
fetch
content-type: ......
---------------------------
String(ArrayBuffer)
ArrayBuffer
將作為 Request body 發(fā)送锣尉,與 Blob/File
相似刻炒,不同之處在于:在發(fā)送請求時,必須要在 Request.Headers 中指定 content-type
自沧,否則會請求失敗坟奥。(而 Blob/File
Body 則無需,在未指定的情況下會使用 application/octet-stream
作為 content-type
默認(rèn)值)