文:志俊(沪江Web前端)javascript
本文原创,转载请注明做者及出处前端
在使用React Native
开发中,咱们熟练的采用JavaScript
的方式发送请求的方式发送一个请求到服务端,可是处理这个请求的过程其实和处理Web
应用中发送的请求的过程是不同的。由于处理这个请求的目标不是浏览器,而是嵌入这个应用的原生操做系统。java
在处理React Native
的请求时,分为两部分:一部分是JavaScript
的运行环境,另外一部分是嵌入JavaScript
的Native
(即原生Android
和IOS
)运行环境。React Native
内置了三种发送网络请求的方式:fetch
, XMLHttpRequest
和 WebSocket
。可是React Native
的运行环境和Web应用的运行环境不同,因此须要在原生应用层采用自定义函数来拓展运行时(runtime)环境来处理JavaScript
发出的网络请求。react
XHR
是Web开发中用得比较多的发送请求的方式,
Fetch
和
Websocket
也是后起之秀,在不少现代Web应用中得以采用。可是,在
React Native
中,这些对象的使用和Web应用是有差异的。当你在JS层调用网络请求时,实际上是经历了两个过程才到达真正的服务器端。就像头部banner表示的那样。
在React Native
中, XMLHttpRequest(XHR)
由两部分组成: “前端”(front-end)和“后端”(back-end)。前端负责与JavaScript
交互,后端负责在原平生台上转换JavaScript
发送过来的请求为原生系统本身的请求。git
这里的后端实际上是一个原平生台顶层抽象的统一API层,使得JavaScript
层能够调用原先系统的网络模块。例如IOS
下内置的URLSession模块和Android
下的OKHTTP模块。github
在现代Web浏览器中,Fetch
API提供了和XHR
大部分相同的功能,可是Fetch
提供了一种更加简单,高效的方式来跨网络异步获取资源,同时可操纵Request
和Response
对象来复用请求。web
可是在React Native
中,为了兼容两种平台的差别,采用了依赖于XMLHttpRequest
的Fetch Polyfill来实现这个请求对象。这就意味着咱们不能像实用Web平台下的Fetch
对象同样来实用React Native
下的该对象。好比采用这个对象来发送binary数据。固然能够采用第三方的库好比react-native-fetch-blob来实现相应的功能。正则表达式
Websocket
做为一种新的通讯协议,采用全双工通信方式与服务器间进行通讯的网络技术。chrome
在React Native
中,Websocket
并非一个独立的请求,和XMLHttpRequest(XHR)
同样由两部分组成: “前端”(front-end)和“后端”(back-end)。前端负责与JavaScript
交互,后端负责在原平生台上转换JavaScript
发送过来的请求为原生系统本身的请求。在IOS中采用的是本身开发的NSStream,而在Android系统中则是OKHTTP模块。npm
在React Native
开发中,你能够经过Chrome Developer Tools (CDT)
的Sources
面板中调试javascript
部分的代码,包括断点、输出信息、断点调试等一切javascript
调试所需的信息。可是,惟一缺乏的就是网络请求的跟踪调试。咱们没办法像Web开发那样,能够经过CDT
中的网络面板(Network
)来查看应用的网络请求的相关信息。
虽然没有办法经过CDT
查看应用的网络请求,可是咱们能够经过Fiddler
、CharlesProxy
及Wireshark
等软件设置代理,来查看追踪调试网络请求。这里使用Fiddler
来做为代理。
首先设置Fiddler
的代理端口: 打开Filddler -> Tool -> Options -> Connects,在监听端口处填写相应的端口号,
在调试机器上、Android
或者IOS
模拟器模拟器中设置代理: 找到调试的机器上的网络设置中,设置当前链接的WIFI的代理地址
刷新应用,在fiddler
中查看网络请求(提示:右键,在新页签中打开可查看清晰图片):
在代理应用中,咱们能够查看请求头,返回头,返回结果等相关的网络信息。固然,还能够根据相关代理软件拦截请求,从新设置后发送。
上面经过设置代理的方式来查看和追踪网络请求,虽然功能强大,可是实际操做起来有些难度,上手成本比较高。经过使用Reactotron
,能够将调试的配置信息集成到应用中,方便在不一样的开发环境下有相同的调试配置,节约开发配置成本。
Reactotron
由两部分组成,一部分是调试应用,一部分是调试配置。
NPM
安装reactotron-cli
npm install -g reactotron-cli
复制代码
在你的`React Native`应用中安装`reactotron-react-native`
```
npm i --save-dev reactotron-react-native
```
而后,在你的应用的添加配置文件,定制调试内容:
```
import Reactotron, {
trackGlobalErrors,
openInEditor,
overlay,
asyncStorage,
networking
} from 'reactotron-react-native'
Reactotron
.configure({
name: 'xxx' // 调试的名称
})
.use(trackGlobalErrors()) // 设置监听全局错误
.use(openInEditor()) // 设置在编辑器中打开错误
.use(overlay()) // 设置图片遮盖图片(用于UI还原度对比)
.use(asyncStorage()) // 设置异步存储调试
.use(networking()) // 设置网络调试
.connect() // 链接应用(必须)
```
而后在你的应用的入口文件中引入这个配置文件。而后从新启动应用。固然,还可使用正则表达式过滤请求的`contentType`的类型和要忽略的请求的`url`,见下面的配置:
```
.use(networking({
ignoreContentTypes: /^(image)\/.*$/i, // 设置reactotron要忽略的文件类型
ignoreUrls: /\/(logs|symbolicate)$/, // 设置reactotron要忽略的url请求路径
}))
```



复制代码
reactotron
调试网络只是他的一个功能之一,其余还有不少强大的功能。有兴趣能够查看他的文档。
React Native
默认暴露出来的接口中,是没有直接在Chrome Developer Tools
查看网络请求的方法的,查看 RN 源码 Libraries/Core/InitializeCore.js,注释中写着:
Sets an object’s property. If a property with the same name exists, this will replace it but maintain its descriptor configuration. By default, the property will replaced with a lazy getter. * The original property value will be preserved as original[PropertyName] so that, if necessary, it can be restored. For example, if you want to route network requests through DevTools (to trace them): * global.XMLHttpRequest = global.originalXMLHttpRequest; * @see github.com/facebook/re…
具体实如今XHRInterceptor.js中。原来的XMLHttpRequest
被改写成了 originalXMLHttpRequest
,因此要在Chrome
中显示network
只须要替换XMLHttpRequest
为 originalXMLHttpRequest
。在入口文件处设置:
if (__DEV__) {
GLOBAL.XMLHttpRequest = GLOBAL.originalXMLHttpRequest || GLOBAL.XMLHttpRequest
}
复制代码
固然,这样有可能会产生CORS
, Chrome
会限制跨域请求。这时要么后端配合一下去除限制,要么使用 Allow-Control-Allow-Origin: * 插件。
因为React Native
中Fetch
对象的底层采用的是XHR
实现,这就限制了发送二进制数据的功能。固然React Native
提供了一系列的方式来解决这个问题,好比: 转换二进制文件为base64字符串或者采用第三方库 react-native-fetch-blob。可是并无从底层解决这个问题。
到目前为止,React Native
不能发送非序列化的数据,因此,要发送二进制数据,采用Base64编码的字符串是个不错的选择。
例如,你从服务器下载一张图片(注意:不是经过url
从服务器获取),请求经过JavaScript线程,再经过React Native
提供的桥接器,最后经过原生系统的网络模块发送到服务端。服务端返回一个Base64编码过的图片,JavaScript
线程收到返回的字符串后,会分配相应的内存,而后React Native
会调用相应的原生模块渲染成相应图片。可是值得主要的是,这种方式会形成典型的性能问题——内存泄漏。
经过Base64编码的方式传输二进制文件,这里会形成一系列性能问题,这篇文章中列出了大部分性能问题及提出了相应的解决方案。
如今使用的各类方法发送二进制文件都存在各类问题,最终的解决方式是要相应的标准可以实现二进制的传输。目前,WebSocket
已经支持了二进制传输。在最新版本的React Native
层也已经支持WebSocket
协议来传输二进制文件,可是,相应的原平生台的网络模块暂时还不支持。
React Native
开发方式是很是不错的体验,可是,受各个平台差别和标准的限制,不得不折中处理一些问题。随之而来的是相应的性能、效率的问题。另外,采用开发,性能上和用户体验上和原生应用仍是有必定差距。可是若是在原生应用中可以集成React Native
,会显著提升开发效率。
2019年,iKcamp原创新书《Koa与Node.js开发实战》已在京东、天猫、亚马逊、当当开售啦!