這是fly的第五篇文章,主要介紹fly最強大的功能-請求重定向。在閱讀本文以前,若是您還不瞭解 fly。 請先閱讀前兩篇文章:
第一篇: JS HTTP 請求終極解決方案 - fly.js
第二篇: Fly vs axios
第三篇:微信小程序中使用Fly 發起http請求
fly gibhub地址:github.com/wendux/flyjavascript
若是你開發的是一個 PC桌面應用、或者一個APP,可能有些功能你須要以經過內嵌 h5 頁面的方式實現,對於這類應用,咱們稱之爲混合應用。而在大所數平臺的混合應用中,你會發現有個問題:你沒法干涉 webview 中 h5 頁面發起的 ajax 請求。這樣一來,你就很難進行統一的請求管理!爲何要進行統一的請求管理呢?主要有如下幾種場景:java
混合APP種很是關鍵的一點就是 Native 和 h5 之間的 cookie 同步。由於 Native 和 h5 均可以發起網絡請求,而二者所用的請求池並非同一個(h5 ajax 請求是 webview 發起的),這就會致使 Native 和 h5 cookie 不能同步,若是不能統一管理請求,就會致使你要在不一樣的場景作大量的同步工做。更沮喪的是,在ios系統中WKWebview並無提供 cookie 同步的接口,而開發者一般只能經過注入 javascript 的方式間接實現,可是,這種作法有個缺點,就是沒法同步 httpOnly 屬性的 cookie , 那是由於 javascript 沒法操做具備httpOnly屬性的cookie ( 這主要是由於現代瀏覽器爲了防止xss攻擊成功後確保用戶cookie不會被惡意腳本竊取而添加的特性 )。node
爲了網絡傳輸數據安全,https協議已經愈來愈普及,可是,瀏覽器/webview 對於https請求,默認的證書校驗策略是:先查看本地證書信任列表,若是本地信任列表中沒有當前訪問站點的證書,則會去檢驗CA鏈。這也就意味着,若是攻擊者經過僞造的證書開一個代理服務器,而後在本身的手機中手動添加這個僞造證書至本地證書信任列表, 而後攻擊者將手機代理指向其代理服務器,這麼一來, webview在請求接口時,數據將會徹底暴漏在攻擊者面前。而目前防止代理攻擊的主要方式就是在端上進行證書校驗,這能夠保證Native發起的請求數據是安全的,可是h5經過webview發起的請求仍將會暴漏,若是你的APP是一個金融理財類的應用,這將很是危險。ios
因爲瀏覽器的同源策略,若是h5請求須要跨域,是一件比較麻煩的事。如今的主流的跨域方案,不管是jsonp,仍是經過設置CORS(Cross Origin Resource Sharing)相關的請求頭,都須要服務端支持。然而不少時候咱們須要能在端上指定哪些域能夠訪問,哪些域不能訪問,若是請求在webview中發起,端上根本沒法干涉。git
不一樣webview,底層對網絡請求處理策略每每會有不一樣,有的是採用一個線程池,有的是每次請求都會建立一個新的線程,這就致使在有些系統上原生webview的請求會相對較慢。github
如今有些混合app爲了實現頁面秒開,都採用一些緩存自管理的方案,常見的就是將線上新版本的h5頁面提早打包,而後在沒次APP啓動後檢測更新、下載。而後攔截 webview 的全部請求,對於靜態資源,直接從下載好的文件中讀取,而動態數據則經過ajax去後臺動態拉去,若是隻是這樣,那倒沒什麼問題,可是,有時有些靜態資源也是須要經過ajax去拉取,好比,一個配置 json, 又或是一個 md格式的幫助文檔。若是不能攔截ajax請求,也就意味着這些靜態資源仍是要經過網絡去服務端拉取。web
綜上所屬,若是能在端上進行統一的請求管理,上面這些問題將會引刃而解。可是,如何實如今端上進行統一的請求管理。咱們說過,目前對於大多數平臺的webview,它們發起的 ajax請求,native 都是沒法直接干涉的。那麼如今有了Fly,咱們應該如何解決這個問題?ajax
在瀏覽器中,Ajax請求都是瀏覽器發出的,而 Fly 能夠經過更換 http engine的方式,將請求重定向到。典型的場景就是在混合 App中,將全部的請求轉發到 Native,而後在Native上進行統一的請求管理、cookie管理、證書校驗、請求過濾等,還有重要的一點就是端上並無同源限制,也能夠在端上作訪問控制。而 Fly 最重要的一個功能就是支持請求重定向。npm
在瞭解請求重定向以前,你須要先了解一些 「http engine」。json
Fly引入了Http engine 的概念,所謂 Http Engine,就是指真正發起 http 請求的引擎,這在瀏覽器中就是
XMLHttpRequest
或ActiveXObject
(IE),而在node環境中,engine 能夠用任何能發起網絡請求的庫或模塊。而 Fly 正是經過在不一樣環境切換不一樣engine的方式實現支持不一樣的javascript運行環境的。
var fly=require("flyio")
//瀏覽器環境下
fly.engine=XMLHttpRequest
//node環境
fly.engine=xx //任何實現了engine接口的對象複製代碼
上面代碼示意了 fly 如何切換 engine,那麼如何來提供自定義的engine?
本質上來說,engine 就是一個和XMLHttpRequest
有相同接口、屬性、行爲的對象。顯然,若是要本身純手工實現一個 engine會很複雜,由於這必須得了解 XMLHttpRequest
的各個細節!
爲了簡化 engine 的實現,Fly 提供了一個 engine-wrapper 模塊,它是一個 engine 的骨架,開發者只須要實現一個適配器(adapter)即可方便的自動生成一個 engine。
下面咱們看看Fly內置的 node engine 是如何使用 engine-wrapper 來實現的:
var Fly = require("../../dist/npm/fly")
var EngineWrapper = require("../../dist/npm/engine-wrapper")
//引入fly實現的node adapter
var adapter = require("./adapter/node")
//經過包裝node adapter生成一個engine
var engine=EngineWrapper(adapter)
module.exports=new Fly(engine)複製代碼
能夠看出,EngineWrapper
能夠經過一個 adapter直接生成一個engine, 那麼如今的工做就轉化爲如何實現一個adapter了,後面咱們會詳細介紹,如今咱們看一下engine惟一的 API:
engine.setAdapter (adpter)
每一個 engine 均可以隨時切換adpter,這能夠實現和切換 http engine相同的目的。
經過上面的例子能夠看出,真正的 http請求動做是在 adapter 中完成的。而adapter是一個標準的接口,簽名以下:
function (request, responseCallBack)複製代碼
request
http請求信息,由engine-wrapper 傳給adapter,基本結構字段以下:
{
method:"",//請求方法, GET 、POST ...
headers:{},//請求頭
url:"",//請求地址
timeout:"",//超時時間
body //請求數據,GET請求時爲null,類型不定,多是FromData、字符串。
}複製代碼
responseCallBack(response)
響應回調,請求結束時adapter應調用此函數,通知engine-wrapper請求結束, response 基本結構字段以下:
{
responseText: '{"aa":5}',//響應內容,爲字符串
statusCode: 200,// http 狀態碼,發生異常時,值爲0
errMsg:"", //錯誤信息,
headers: {}//響應頭
}複製代碼
整個請求過程爲:每次請求開始的時候,fly 將用戶本次的請求信息傳給 http engine,而後 http engine 根據用戶請求信息生成一個 request 對象傳遞給 adapter, 接着 adapter 發起真正的 http 請求,等到請求結束時,adapter 經過調用 responseCallBack
將請求結果回傳給 http engine. 而後 http engine 將結果返回給fly。
基本結構字段:
所謂基本結構字段就是指fly定義的標準字段。除了這些基本結構字段,也能夠任意擴展自定義字段。
對於 request對象, 用戶在發起的請求配置 options 中的其它字段也會 merge 到 request 對象中,這樣就能夠在adapter 中獲取到,這在自定義 adapter時很是有用。
對於 response 對象,能夠在 adapter 中給其添加任何自定義字段,這些自定義字段會經過engine直接傳遞給fly,因此你能夠在 then回調中取出。
var engine= EngineWrapper(function (request,responseCallback) {
responseCallback({
statusCode:200,
responseText:"你變或者不變,我都不變😜。",
extraFeild:"自定義字段"
})
})
fly.engine=engine;
fly.get("../package.json").then(d=>{
log(d.data)
log(d.extraFeild)
})
控制檯輸出
> 你變或者不變,我都不變😜。
> 自定義字段複製代碼
在這個例子中,adapter 並無真正發起 http 請求,而是直接返回了固定內容,這樣 fly 上層請求任何接口收到的內容永遠都是相同的。
咱們說過,在瀏覽器環境中,fly 使用的默認engine 就是 XMLHttpRequest
。如今咱們想一想混合APP, 若是能在 Native 上實現一個engine,而後供瀏覽器中的 fly 使用,那麼也就會將本來應該在瀏覽器中發起的請求重定向到了 Native 上。而這個在 Native 上實現的 engine,咱們稱其爲遠程 engine,這是由於調用者和執行者並不在同一個環境。在介紹在fly中如何使用遠程 engine以前,咱們得先來了解一下什麼是 Javascript Bridge 。
Javascript Bridge 是指web應用中Javascript與Native之間接口互調,數據傳輸的一個橋樑。如今github中有一些成熟易用的移動端跨平臺實現如: dsBridge 、 WebViewJavascriptBridge 。
經過 Javascript bridge,咱們能夠在 adapter 中將請求信息轉發到 Natvie上,而後在 native 上根據請求信息發起真正的網絡請求。這樣作的好處就是能夠在native進行統一的證書驗證、cookie管理、訪問控制 、緩存策略等等。等到native請求完成後再將請求結果回傳給 adapter , 而後 adapter 再返回給 fly,整個請求流程結束。
由於不一樣的 Javascript bridge, 數據傳輸的協議不一樣,咱們只需爲咱們使用的 javascript bridge 提供一個 adapter 便可。fly 預置了 DSBridge 的 adapter 。
dsBridge 是一個優秀的跨平臺的 Javascript Bridge ,最大的特色是不只支持異步調用,也支持同步調用和進度連續調用。若是你的 App 使用的是DSBridge, 那麼你能夠很是方便的使用fly。
var adapter = require("flyio/dist/npm/adapter/dsbridge")
var EngineWrapper = require("flyio/dist/npm/engine-wrapper")
var Fly = require("flyio/dist/npm/fly")
var dsEngine = EngineWrapper(adapter)
var fly = new Fly(engine);
//而後你就可使用fly發起請求了
fly.get("xxx.com")...複製代碼
如今在h5中經過fly發起的全部ajax請求都會被重定向到端上。
Fly 將 http 請求重定向到 Native ,Native 是須要完成真正的 http 請求。具體實現由端上根據使用的網絡框架自定,下一篇文章咱們將從頭開始實現一個了Android端的http engine,若是你感興趣,能夠關注我。
再次貼出fly github地址,若是你喜歡,歡迎star,以使更多的人知道fly,感謝您的支持: github: fly.js