React Native Fetch 问题

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 未实现 arrayBufferstreamtext 方法。
② 创建 Blob 对象 new Blob(array, options) 中的 array 参数,RN 只能使用 StringBlob,而不能使用 ArrayBufferArrayBufferView

关于 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-typewhatwg-fetch 实现,以下 header content-type 则在原生的 Android 端iOS 端 实现 )

fetch
content-type: multipart/form-data; boundary=...
---------------------------
String(FormData)

不同之处:根据 FormData 文档RN 源码,可以看到有以下不同
① RN 仅实现了 appendgetParts 方法,而没有实现 gethasset 等方法。如果在 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 中的其他 StringBlob 对象整合为一个统一的 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 默认值)

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,716评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,558评论 1 294
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,431评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,127评论 0 209
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,511评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,692评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,915评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,664评论 0 202
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,412评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,616评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,105评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,424评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,098评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,096评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,869评论 0 197
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,748评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,641评论 2 271

推荐阅读更多精彩内容