Fetch Request
web 環境下 Request Body 支持的 參數 類型有: String
, URLSearchParams
, Blob/File
, FormData
, ArrayBuffer
, ArrayBufferView
不同之處:
① RN 自身本僅支持 XMLHttpRequest
進行網絡請求,支持的 Request Body 可通過 源碼1 > 源碼2 > 源碼3 查看,缺少了對 URLSearchParams
的支持。
② RN Fetch 使用 whatwg-fetch
,通過 XMLHttpRequest
實現了 Fetch
功能,根據 源碼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
不同之處:根據 web 示例,支持 new URLSearchParams("foo=foo&bar=bar")
,但根據 RN 源碼,僅支持 new URLSearchParams({foo:"foo", bar:"bar"})
形式,且沒有實現 get、has、set 等方法。
Blob/File
body 為 Blob
,請求格式如下
fetch
content-type: Blob.type
---------------------------
String(Blob)
不同之處:根據 Blob 文檔 和 RN 源碼
① 可以看到 RN Blob
未實現 arrayBuffer
、stream
、text
方法。
② 創建 Blob
對象 new Blob(array, options)
中的 array
參數,RN 只能使用 String
和 Blob
,而不能使用 ArrayBuffer
、ArrayBufferView
關于 RN Blob
(File 是繼承 Blob
實現的,二者基本一致,不再累述):
在瀏覽器中,Blob
對象的數據緩存在瀏覽器中并與變量指針綁定。在 RN 中,Blob
對象的數據將緩存在原生端(其實也就是 app 運行內存中),并生成一個唯一的 id,返回給 js 端,也就是說在 js 端存儲的僅是一個 id。后續則可通過 FileReader 與原生端交互,讀取 Blob
對象的實際數據。Fetch
函數內部已實現了數據讀取,可將 Blob
直接設置為 Request Body
。
Blob
的創建方式:
① 通過函數,比如 Fetch
/ XMLHttpRequest
請求可以獲取到 Response Blob,網絡請求是在原生端完成的,完成后原生端緩存響應結果,返回唯一 id 給 js 端創建 Blob。
② 也可以使用如下方法直接創建,js 會先將創建數據傳遞給原生端緩存,然后使用原生端返回的唯一 id 創建 Blob
const body = new Blob(
['<a id="a"><b id="b">hey!</b></a>'],
{type : 'text/html', lastModified:Date.now()}
);
-> 創建 -> string 傳到原生端 -> 返回 id -> js{id:....,type,}
const stream = new Blob(
[body, 'string'],
{type : 'text/html', lastModified:Date.now()}
);
-> 傳遞參數 body 的 id 和 string -> 返回新 id -> js{id:...,type,}
FormData
body 為 Blob
,請求格式如下 (以上 body
格式的 header content-type
由 whatwg-fetch
實現,以下 header content-type
則在原生的 Android 端、iOS 端 實現 )
fetch
content-type: multipart/form-data; boundary=...
---------------------------
String(FormData)
不同之處:根據 FormData 文檔 和 RN 源碼,可以看到有以下不同
① RN 僅實現了 append
、getParts
方法,而沒有實現 get
、has
、set
等方法。如果在 RN 中需要對已添加的 form data 進行修改,可通過 FormData._parts
進行操作,但這種方法并不安全,后續 RN 可能會對 _parts
更新,造成兼容性問題。
② append 方法與瀏覽器端的實現不同
// 瀏覽器, 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',
});
關于 RN FormData
的幾點說明
- 查看 iOS源碼 和 Android 源碼,可以看出在原生端 RN 并未支持 FormData 添加 Blob 類型數據。
- RN 給了另外一種上傳文件的方式,通過
{uri, ...}
指定文件地址,uri
支持file://
,content://
(Android), 甚至還支持http://
網絡圖片 - 如果必須要求
FormData
支持Blob
對象,有兩種拓展思路(需自行實現)- 先將
Blob
對象保存為臨時文件,然后通過{uri, ...}
添加,待請求完成后刪除臨時文件,這種方式會產生臨時文件,且本來Blob
對象已在內存中,保存為文件,發送請求,原生端會再次讀取臨時文件到內存中,有點浪費。 - Request body 支持
Blob
對象,可根據 規則 自行將formData
轉換為multipart/form-data
類型的Blob
數據,如果formData
中包含{uri, ...}
類型文件,則需要將該類型轉為Blob
對象才能與formData
中的其他String
、Blob
對象整合為一個統一的Blob
對象,實現起來略微麻煩點。 - 所以,如果可以調整思路避開使用
FormData Blob
,就盡量避開吧
- 先將
ArrayBuffer / ArrayBufferView
fetch
content-type: ......
---------------------------
String(ArrayBuffer)
ArrayBuffer
將作為 Request body 發送,與 Blob/File
相似,不同之處在于:在發送請求時,必須要在 Request.Headers 中指定 content-type
,否則會請求失敗。(而 Blob/File
Body 則無需,在未指定的情況下會使用 application/octet-stream
作為 content-type
默認值)