React Native 網路層分析
文:志俊
本文原創,轉載請註明作者及出處
在使用 開發中,我們熟練的採用 的方式發送請求的方式發送一個請求到服務端,但是處理這個請求的過程其實和處理 應用中發送的請求的過程是不一樣的。因為處理這個請求的目標不是瀏覽器,而是嵌入這個應用的原生操作系統。
在處理 的請求時,分為兩部分:一部分是 的運行環境,另一部分是嵌入 的 (即原生 和 i)運行環境。 內置了三種發送網路請求的方式: , 和 。但是 的運行環境和 Web 應用的運行環境不一樣,所以需要在原生應用層採用自定義函數來拓展運行時(runtime)環境來處理 發出的網路請求。
請求發送方式及過程
對於常用的網路請求對象:XMLHttpRequest(XHR)、Fetch 及 WebSocket,熟悉前端開發的同學應該非常了解。 是Web開發中用得比較多的發送請求的方式, 和 也是後起之秀,在很多現代 Web 應用中得以採用。但是,在 中,這些對象的使用和 Web 應用是有差別的。當你在 JS 層調用網路請求時,其實是經歷了兩個過程才到達真正的伺服器端。就像頭部 banner 表示的那樣。
XMLHttpRequest(XHR)
在 中, 由兩部分組成: 「前端」(front-end)和「後端」(back-end)。前端負責與 交互,後端負責在原生平台上轉換 發送過來的請求為原生系統自己的請求。
這裡的後端其實是一個原生平台頂層抽象的統一API層,使得 層可以調用原先系統的網路模塊。例如 iOS下內置的 URLSession 模塊和下的 OKHTTP模塊。
Fetch
在現代 Web 瀏覽器中, API 提供了和 大部分相同的功能,但是 提供了一種更加簡單,高效的方式來跨網路非同步獲取資源,同時可操縱 和 對象來複用請求。
但是在 中,為了兼容兩種平台的差異,採用了依賴於 的 Fetch Polyfill 來實現這個請求對象。這就意味著我們不能像實用 Web 平台下的 對象一樣來實用 下的該對象。比如採用這個對象來發送 binary 數據。當然可以採用第三方的庫比如 react-native-fetch-blob 來實現相應的功能。
Websocket
作為一種新的通信協議,採用全雙工通訊方式與伺服器間進行通信的網路技術。
在 中, 並不是一個獨立的請求,和 一樣由兩部分組成: 「前端」(front-end)和「後端」(back-end)。前端負責與 交互,後端負責在原生平台上轉換 發送過來的請求為原生系統自己的請求。在 iOS 中採用的是自己開發的 NSStream,而在 Android 系統中則是OKHTTP 模塊。
查看React Native中的網路請求
在 開發中,你可以通過 的 面板中調試 部分的代碼,包括斷點、輸出信息、斷點調試等一切 調試所需的信息。但是,唯一缺少的就是網路請求的跟蹤調試。我們沒辦法像 Web 開發那樣,可以通過 中的網路面板( )來查看應用的網路請求的相關信息。
使用代理調試網路請求
雖然沒有辦法通過 查看應用的網路請求,但是我們可以通過 、 及 等軟體設置代理,來查看追蹤調試網路請求。這裡使用 來作為代理。
1.首先設置 的代理埠: 打開 Filddler -> Tool -> Options -> Connects,在監聽埠處填寫相應的埠號,
2.在調試機器上、 或者 i模擬器模擬器中設置代理: 找到調試的機器上的網路設置中,設置當前連接的 WIFI 的代理地址
3.刷新應用,在 中查看網路請求
GIF
在代理應用中,我們可以查看請求頭,返回頭,返回結果等相關的網路信息。當然,還可以根據相關代理軟體攔截請求,重新設置後發送。
使用 Reactotron 調試網路
上面通過設置代理的方式來查看和追蹤網路請求,雖然功能強大,但是實際操作起來有些難度,上手成本比較高。通過使用 ,可以將調試的配置信息集成到應用中,方便在不同的開發環境下有相同的調試配置,節約開發配置成本。
由兩部分組成,一部分是調試應用,一部分是調試配置。
1.調試應用分別有各個操作系統的 GUI 安裝版本。當然,如果習慣使用命令行,也可以使用 安裝
2.設置調試配置:
GIF
調試網路只是他的一個功能之一,其他還有很多強大的功能。有興趣可以查看他的文檔。
使用 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 中。原來的 被改寫成了 ,所以要在 中顯示 只需要替換 為 。在入口文件處設置:
當然,這樣有可能會產生 , 會限制跨域請求。這時要麼後端配合一下去除限制,要麼使用 Allow-Control-Allow-Origin: * 插件。
React Native發送二進位數據(binary data )
由於 中 對象的底層採用的是 實現,這就限制了發送二進位數據的功能。當然 提供了一系列的方式來解決這個問題,比如: 轉換二進位文件為 Base64 字元串或者採用第三方庫 react-native-fetch-blob。但是並沒有從底層解決這個問題。
轉換二進位為 Base64 發送
到目前為止, 不能發送非序列化的數據,所以,要發送二進位數據,採用 Base64 編碼的字元串是個不錯的選擇。
例如,你從伺服器下載一張圖片(注意:不是通過 從伺服器獲取),請求通過JavaScript 線程,再通過 提供的橋接器,最後通過原生系統的網路模塊發送到服務端。服務端返回一個 Base64 編碼過的圖片, 線程收到返回的字元串後,會分配相應的內存,然後 會調用相應的原生模塊渲染成相應圖片。但是值得主要的是,這種方式會造成典型的性能問題——內存泄漏。
通過 Base64 編碼的方式傳輸二進位文件,這裡會造成一系列性能問題,這篇文章中列出了大部分性能問題及提出了相應的解決方案。
現在使用的各種方法發送二進位文件都存在各種問題,最終的解決方式是要相應的標準能夠實現二進位的傳輸。目前, 已經支持了二進位傳輸。在最新版本的 層也已經支持 協議來傳輸二進位文件,但是,相應的原生平台的網路模塊暫時還不支持。
總結
開發方式是非常不錯的體驗,但是,受各個平台差異和標準的限制,不得不折中處理一些問題,隨之而來的是相應的性能、效率的問題。另外,採用開發,性能上和用戶體驗上和原生應用還是有一定差距。但是如果在原生應用中能夠集成 ,會顯著提高開發效率。
參考
Network layer in React Native
reactotron介紹
reactotron
Reactotron on React Native
End
TAG:滬江技術學院 |