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
默认值)
网友评论