React Native 網絡層分析

文:志俊(滬江Web前端)javascript

本文原創,轉載請註明做者及出處前端

在使用React Native開發中,咱們熟練的採用JavaScript的方式發送請求的方式發送一個請求到服務端,可是處理這個請求的過程其實和處理Web應用中發送的請求的過程是不同的。由於處理這個請求的目標不是瀏覽器,而是嵌入這個應用的原生操做系統。java

banner

在處理React Native的請求時,分爲兩部分:一部分是JavaScript的運行環境,另外一部分是嵌入JavaScriptNative(即原生AndroidIOS)運行環境。React Native內置了三種發送網絡請求的方式:fetch, XMLHttpRequestWebSocket。可是React Native的運行環境和Web應用的運行環境不同,因此須要在原生應用層採用自定義函數來拓展運行時(runtime)環境來處理JavaScript發出的網絡請求。react

請求發送方式及過程

banner
對於經常使用的網絡請求對象:XMLHttpRequest(XHR)、Fetch及WebSocket,熟悉前端開發的同窗應該很是瞭解。 XHR是Web開發中用得比較多的發送請求的方式, FetchWebsocket也是後起之秀,在不少現代Web應用中得以採用。可是,在 React Native中,這些對象的使用和Web應用是有差異的。當你在JS層調用網絡請求時,實際上是經歷了兩個過程纔到達真正的服務器端。就像頭部banner表示的那樣。

XMLHttpRequest(XHR)

React Native中, XMLHttpRequest(XHR)由兩部分組成: 「前端」(front-end)和「後端」(back-end)。前端負責與JavaScript交互,後端負責在原平生臺上轉換JavaScript發送過來的請求爲原生系統本身的請求。git

這裏的後端實際上是一個原平生臺頂層抽象的統一API層,使得JavaScript層能夠調用原先系統的網絡模塊。例如IOS下內置的URLSession模塊和Android下的OKHTTP模塊。github

Fetch

在現代Web瀏覽器中,FetchAPI提供了和XHR大部分相同的功能,可是Fetch提供了一種更加簡單,高效的方式來跨網絡異步獲取資源,同時可操縱RequestResponse對象來複用請求。web

可是在React Native中,爲了兼容兩種平臺的差別,採用了依賴於XMLHttpRequestFetch Polyfill來實現這個請求對象。這就意味着咱們不能像實用Web平臺下的Fetch對象同樣來實用React Native下的該對象。好比採用這個對象來發送binary數據。固然能夠採用第三方的庫好比react-native-fetch-blob來實現相應的功能。正則表達式

Websocket

Websocket做爲一種新的通訊協議,採用全雙工通信方式與服務器間進行通訊的網絡技術。chrome

React Native中,Websocket並非一個獨立的請求,和XMLHttpRequest(XHR)同樣由兩部分組成: 「前端」(front-end)和「後端」(back-end)。前端負責與JavaScript交互,後端負責在原平生臺上轉換JavaScript發送過來的請求爲原生系統本身的請求。在IOS中採用的是本身開發的NSStream,而在Android系統中則是OKHTTP模塊。npm

查看React Native中的網絡請求

React Native開發中,你能夠經過Chrome Developer Tools (CDT)Sources面板中調試javascript部分的代碼,包括斷點、輸出信息、斷點調試等一切javascript調試所需的信息。可是,惟一缺乏的就是網絡請求的跟蹤調試。咱們沒辦法像Web開發那樣,能夠經過CDT中的網絡面板(Network)來查看應用的網絡請求的相關信息。

使用代理調試網絡請求

雖然沒有辦法經過CDT查看應用的網絡請求,可是咱們能夠經過FiddlerCharlesProxyWireshark等軟件設置代理,來查看追蹤調試網絡請求。這裏使用Fiddler來做爲代理。

  1. 首先設置Fiddler的代理端口: 打開Filddler -> Tool -> Options -> Connects,在監聽端口處填寫相應的端口號,

    fiddler設置

  2. 在調試機器上、Android或者IOS模擬器模擬器中設置代理: 找到調試的機器上的網絡設置中,設置當前鏈接的WIFI的代理地址

    fiddler設置

  3. 刷新應用,在fiddler中查看網絡請求(提示:右鍵,在新頁籤中打開可查看清晰圖片):

    fiddler設置

在代理應用中,咱們能夠查看請求頭,返回頭,返回結果等相關的網絡信息。固然,還能夠根據相關代理軟件攔截請求,從新設置後發送。

使用Reactotron調試網絡

上面經過設置代理的方式來查看和追蹤網絡請求,雖然功能強大,可是實際操做起來有些難度,上手成本比較高。經過使用Reactotron,能夠將調試的配置信息集成到應用中,方便在不一樣的開發環境下有相同的調試配置,節約開發配置成本。

Reactotron由兩部分組成,一部分是調試應用,一部分是調試配置。

  1. 調試應用分別有各個操做系統的GUI安裝版本。固然,若是習慣使用命令行,也可使用NPM安裝reactotron-cli
npm install -g reactotron-cli
複製代碼

reactotron設置

  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 github.com/facebook/re…

具體實如今XHRInterceptor.js中。原來的XMLHttpRequest被改寫成了 originalXMLHttpRequest,因此要在Chrome 中顯示network 只須要替換XMLHttpRequestoriginalXMLHttpRequest。在入口文件處設置:

if (__DEV__) {
  GLOBAL.XMLHttpRequest = GLOBAL.originalXMLHttpRequest || GLOBAL.XMLHttpRequest
}
複製代碼

固然,這樣有可能會產生CORS, Chrome 會限制跨域請求。這時要麼後端配合一下去除限制,要麼使用 Allow-Control-Allow-Origin: * 插件。

React Native發送二進制數據(binary data )

因爲React NativeFetch對象的底層採用的是XHR實現,這就限制了發送二進制數據的功能。固然React Native提供了一系列的方式來解決這個問題,好比: 轉換二進制文件爲base64字符串或者採用第三方庫 react-native-fetch-blob。可是並無從底層解決這個問題。

轉換二進制爲base64發送

到目前爲止,React Native不能發送非序列化的數據,因此,要發送二進制數據,採用Base64編碼的字符串是個不錯的選擇。

banner

例如,你從服務器下載一張圖片(注意:不是經過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實戰項目教學(含視頻)| 課程大綱介紹


2019年,iKcamp原創新書《Koa與Node.js開發實戰》已在京東、天貓、亞馬遜、噹噹開售啦!

相關文章
相關標籤/搜索