文:志俊(沪江Web前端)

本文原创,转载请注明作者及出处

在使用React Native开发中,我们熟练的采用JavaScript的方式发送请求的方式发送一个请求到服务端,但是处理这个请求的过程其实和处理Web应用中发送的请求的过程是不一样的。因为处理这个请求的目标不是浏览器,而是嵌入这个应用的原生操作系统。

在处理React Native的请求时,分为两部分:一部分是JavaScript的运行环境,另一部分是嵌入JavaScript的Native(即原生Android和IOS)运行环境。React Native内置了三种发送网络请求的方式:fetch, XMLHttpRequest 和 WebSocket。但是React Native的运行环境和Web应用的运行环境不一样,所以需要在原生应用层采用自定义函数来拓展运行时(runtime)环境来处理JavaScript发出的网络请求。

请求发送方式及过程



对于常用的网络请求对象:XMLHttpRequest(XHR)、Fetch及WebSocket,熟悉前端开发的同学应该非常了解。XHR是Web开发中用得比较多的发送请求的方式,Fetch和Websocket也是后起之秀,在很多现代Web应用中得以采用。但是,在React Native中,这些对象的使用和Web应用是有差别的。当你在JS层调用网络请求时,其实是经历了两个过程才到达真正的服务器端。就像头部banner表示的那样。

XMLHttpRequest(XHR)

在React Native中, XMLHttpRequest(XHR)由两部分组成: “前端”(front-end)和“后端”(back-end)。前端负责与JavaScript交互,后端负责在原生平台上转换JavaScript发送过来的请求为原生系统自己的请求。

这里的后端其实是一个原生平台顶层抽象的统一API层,使得JavaScript层可以调用原先系统的网络模块。例如IOS下内置的URLSession模块和Android下的OKHTTP模块。

Fetch

在现代Web浏览器中,FetchAPI提供了和XHR大部分相同的功能,但是Fetch提供了一种更加简单,高效的方式来跨网络异步获取资源,同时可操纵Request和Response对象来复用请求。

但是在React Native中,为了兼容两种平台的差异,采用了依赖于XMLHttpRequest的Fetch Polyfill来实现这个请求对象。这就意味着我们不能像实用Web平台下的Fetch对象一样来实用React Native下的该对象。比如采用这个对象来发送binary数据。当然可以采用第三方的库比如react-native-fetch-blob来实现相应的功能。

Websocket

Websocket作为一种新的通信协议,采用全双工通讯方式与服务器间进行通信的网络技术。

在React Native中,Websocket并不是一个独立的请求,和XMLHttpRequest(XHR)一样由两部分组成: “前端”(front-end)和“后端”(back-end)。前端负责与JavaScript交互,后端负责在原生平台上转换JavaScript发送过来的请求为原生系统自己的请求。在IOS中采用的是自己开发的NSStream,而在Android系统中则是OKHTTP模块。

查看React Native中的网络请求

在React Native开发中,你可以通过Chrome Developer Tools (CDT)的Sources面板中调试javascript部分的代码,包括断点、输出信息、断点调试等一切javascript调试所需的信息。但是,唯一缺少的就是网络请求的跟踪调试。我们没办法像Web开发那样,可以通过CDT中的网络面板(Network)来查看应用的网络请求的相关信息。

使用代理调试网络请求

虽然没有办法通过CDT查看应用的网络请求,但是我们可以通过Fiddler、CharlesProxy及Wireshark等软件设置代理,来查看追踪调试网络请求。这里使用Fiddler来作为代理。

  1. 首先设置Fiddler的代理端口:

    打开Filddler -> Tool -> Options -> Connects,在监听端口处填写相应的端口号,

  2. 在调试机器上、Android或者IOS模拟器模拟器中设置代理:

    找到调试的机器上的网络设置中,设置当前连接的WIFI的代理地址

  3. 刷新应用,在fiddler中查看网络请求(提示:右键,在新页签中打开可查看清晰图片):

在代理应用中,我们可以查看请求头,返回头,返回结果等相关的网络信息。当然,还可以根据相关代理软件拦截请求,重新设置后发送。

使用Reactotron调试网络

上面通过设置代理的方式来查看和追踪网络请求,虽然功能强大,但是实际操作起来有些难度,上手成本比较高。通过使用Reactotron,可以将调试的配置信息集成到应用中,方便在不同的开发环境下有相同的调试配置,节约开发配置成本。

Reactotron由两部分组成,一部分是调试应用,一部分是调试配置。

  1. 调试应用分别有各个操作系统的GUI安装版本。当然,如果习惯使用命令行,也可以使用NPM安装reactotron-cli
npm install -g reactotron-cli

  1. 设置调试配置:
在你的`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设置](https://raw.githubusercontent.com/yandan66/blogs/master/source/_posts/20171124/reactotron_02.png)
![reactotron设置](https://raw.githubusercontent.com/yandan66/blogs/master/source/_posts/20171124/reactotron_03.png)
![reactotron结果](https://gitlab.yeshj.com/hujiang-f2e/fun-book/raw/5f6236238c0e51a085d3be32b349436c5e3dad73/%E9%97%A8%E6%88%B7%E7%BA%BF/image/ezgif.com-resize.gif)

reactotron调试网络只是他的一个功能之一,其他还有很多强大的功能。有兴趣可以查看他的文档。

使用Chrome Developer Tools网络面板调试网络

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 https://github.com/facebook/react-native/issues/934

具体实现在XHRInterceptor.js中。原来的XMLHttpRequest 被改写成了 originalXMLHttpRequest,所以要在Chrome 中显示network 只需要替换 XMLHttpRequest 为 originalXMLHttpRequest。在入口文件处设置:

if (__DEV__) {
GLOBAL.XMLHttpRequest = GLOBAL.originalXMLHttpRequest || GLOBAL.XMLHttpRequest
}

当然,这样有可能会产生CORS, Chrome 会限制跨域请求。这时要么后端配合一下去除限制,要么使用 Allow-Control-Allow-Origin: * 插件。

React Native发送二进制数据(binary data )

由于React Native中Fetch对象的底层采用的是XHR实现,这就限制了发送二进制数据的功能。当然React Native提供了一系列的方式来解决这个问题,比如: 转换二进制文件为base64字符串或者采用第三方库react-native-fetch-blob。但是并没有从底层解决这个问题。

转换二进制为base64发送

到目前为止,React Native不能发送非序列化的数据,所以,要发送二进制数据,采用Base64编码的字符串是个不错的选择。

例如,你从服务器下载一张图片(注意:不是通过url从服务器获取),请求通过JavaScript线程,再通过React Native提供的桥接器,最后通过原生系统的网络模块发送到服务端。服务端返回一个Base64编码过的图片,JavaScript线程收到返回的字符串后,会分配相应的内存,然后React Native会调用相应的原生模块渲染成相应图片。但是值得主要的是,这种方式会造成典型的性能问题——内存泄漏。

通过Base64编码的方式传输二进制文件,这里会造成一系列性能问题,这篇文章中列出了大部分性能问题及提出了相应的解决方案。

现在使用的各种方法发送二进制文件都存在各种问题,最终的解决方式是要相应的标准能够实现二进制的传输。目前,WebSocket已经支持了二进制传输。在最新版本的React Native层也已经支持WebSocket协议来传输二进制文件,但是,相应的原生平台的网络模块暂时还不支持。

总结

React Native开发方式是非常不错的体验,但是,受各个平台差异和标准的限制,不得不折中处理一些问题。随之而来的是相应的性能、效率的问题。另外,采用开发,性能上和用户体验上和原生应用还是有一定差距。但是如果在原生应用中能够集成React Native,会显著提高开发效率。

参考

Network layer in React Native

reactotron介绍

reactotron

Reactotron on React Native

推荐: 翻译项目Master的自述:

1. 干货|人人都是翻译项目的Master

2. iKcamp出品微信小程序教学共5章16小节汇总(含视频)

3. 开始免费连载啦~每周2更共11堂iKcamp课|基于Koa2搭建Node.js实战项目教学(含视频)| 课程大纲介绍

React Native 网络层分析的更多相关文章

  1. Hybrid APP基础篇(二)->Native、Hybrid、React Native、Web App方案的分析比较

    说明 Native.Hybrid.React.Web App方案的分析比较 目录 前言 参考来源 前置技术要求 楔子 几种APP开发模式 概述 Native App Web App Hybrid Ap ...

  2. React Native 从入门到原理

    React Native 是最近非常火的一个话题,介绍如何利用 React Native 进行开发的文章和书籍多如牛毛,但面向入门水平并介绍它工作原理的文章却寥寥无几. 本文分为两个部分:上半部分用通 ...

  3. 关于React Native 火热的话题,从入门到原理

    本文授权转载,作者:bestswifter(简书) React Native 是最近非常火的一个话题,介绍如何利用 React Native 进行开发的文章和书籍多如牛毛,但面向入门水平并介绍它工作原 ...

  4. React Native 从入门到原理一

    React Native 从入门到原理一 React Native 是最近非常火的一个话题,介绍如何利用 React Native 进行开发的文章和书籍多如牛毛,但面向入门水平并介绍它工作原理的文章却 ...

  5. React Native 入门到原理(详解)

    抛砖引玉(帮你更好的去理解怎么产生的 能做什么) 砖一.动态配置 由于 AppStore 审核周期的限制,如何动态的更改 app 成为了永恒的话题.无论采用何种方式,我们的流程总是可以归结为以下三部曲 ...

  6. React Native分析(index.ios.js)

    定义创建组件MyComponent(index.ios.js): 'use strict' var React = require('react-native'); var { AppRegistry ...

  7. React Native 4 for Android源码分析 一《JNI智能指针之介绍篇》

    文/ Tamic: http://blog.csdn.net/sk719887916/article/details/53455441 原文:http://blog.csdn.net/eewolf/a ...

  8. H5、React Native、Native应用对比分析

    每日更新关注:http://weibo.com/hanjunqiang  新浪微博!iOS开发者交流QQ群: 446310206 "存在即合理".凡是存在的,都是合乎规律的.任何新 ...

  9. React Native超简单完整示例-tabs、页面导航、热更新、用户行为分析

    初学React Native,如果没有人指引,会发现好多东西无从下手,但当有人指引后,会发现其实很简单.这也是本人写这篇博客的主要原因,希望能帮到初学者. 本文不会介绍如何搭建开发环境,如果你还没有搭 ...

随机推荐

  1. java 拦截器

    一.前言 这是一篇关于 java 拦截器的文章,是我的写 java  web 所遇见的问题.当我们写好一个网站,必须要通过登陆页面才可以进入这个系统.那么我们就得写个 java 拦截器,如果是通过登录 ...

  2. jar包后台启动--nohup篇

    直接java -jar TestHttps-0.0.1-SNAPSHOT.jar的话是前段启动,但是窗口关闭之类的程序也就关闭了 我们可以nohup java -jar TestHttps-0.0.1 ...

  3. git入门(msysgit安装)

    1.下载git-for-windows 常用的GitHub客户端msysgit,也就是git-for-windows. 登录官网 https://git-for-windows.github.io/, ...

  4. Django实战,小网站实现增删改查

    直接上代码 视图: from django.shortcuts import render,render_to_response, redirect from submit import models ...

  5. 【python】函数闭包

    列表时可以改

  6. 【ANT】使用ANT自动执行JMeter用例

    1.把\apache-jmeter-3.1\extras目录下的build.xml和jmeter-results-detail-report_21.xsl两个文件拷贝到用例所在目录: 2.修改用例名称 ...

  7. Spring框架(四)AOP面向切面编程

    一.前言 在以前的项目中,很少去关注spring aop的具体实现与理论,只是简单了解了一下什么是aop具体怎么用,看到了一篇博文写得还不错,就转载来学习一下,博文地址:http://www.cnbl ...

  8. RSA,DES,RC4,3DES ,MD5

    一,RSA算法基于一个十分简单的数论事实:将两个大质数相乘十分容易,但是想要对其乘积进行因式分解却极其困难,因此可以将乘积公开作为加密密钥. RSA算法是一种非对称密码算法,所谓非对称,就是指该算法需 ...

  9. 未来五年什么样的IT技术最具颠覆性?这里有你想知道的答案

    据外媒报道称,近日Gartner研讨会在美国弗罗里达州奥兰多举行,智能化.大数据和物联网成为届研讨会的三大主题.市场研究机构Gartner Research的副总裁兼资深研究员大卫·卡利(David ...

  10. 30分钟入门Java

    技术只是工具,文档只是说明书,仅此而已. 写在前面 工作4年有余,盲人摸象般的走过弯路,也投机取巧的领悟到过一些类似"编程本质"的东西.现在开始我计划回顾下我的编程生涯.在这里分享 ...