前一段時間,項目在對 WKWebview
進行適配時,接觸到了公共能力組使用的 Ajax-hook
方案,因而便對它的怎麼實現的很感興趣,到網上查資料學習時,找到了做者 @wendux 的 Ajax-hook原理解析 這篇文章,當時邊看腦子裏就邊想:「臥槽,這種騷操做怎麼感受 Proxy
也能來一波!」。等看到這篇文章的評論區有個老哥 @銀冰雪千載 也發出了同樣的疑問時,會心一笑,說幹就幹,打開 VSCode 就是一頓操做。javascript
這個東西其實也不新鮮了,不過因爲不支持 IE ,且 Safari 10 纔開始支持,用的時候一直當心翼翼的。一直在尋找一些最佳實踐,此次應該也算是一次練手。對它不太熟的同窗能夠看看 MDN上的Proxy 和 ECMAScript 6入門裏的Proxy 。這次實現,用到了它的get
、set
以及 construct
方法。前端
XMLHttpRequest
咱們並不陌生,雖然在諸如 axios
這類優秀的請求庫幫助下,咱們漸漸不須要直接操做它了,可是對它的熟悉程度不該該停留在表層,在一些瀏覽器適配和前端監控以及埋點的時候,仍是要和它打交道的。在這裏咱們須要明確一些點:java
response
、responseText
、timeout
這類的屬性,姑且稱之爲 普通屬性 onreadystatechange
、onprogress
、onload
這類的屬性,則稱之爲 事件屬性 open
、send
、abort
這類,稱之爲 方法 writable
的,以下圖因此咱們在攔截這些屬性時,要作些特殊處理。ios
這部分建議先看一下 API ,或者打開 API 放在旁邊對照着看,效果更佳。
和 Ajax-hook
同樣,整體是採用代理模式,下面上個整體的原理圖:git
首先,不管項目(瀏覽器端)採用什麼請求方案,只要是最終用的是built-in
對象XMLHttpRequest
,都須要用es6
var xhr = new XMLHttpRequest()
將其實例化,那麼咱們就能夠先攔截 XMLHttpRequest
對象的 new
操做,落實到代碼就是用 Proxy
的 construct
方法。在攔截操做裏,咱們就作簡單的兩件事:github
built-in
對象 XMLHttpRequest
Proxy
繼續攔截 built-in
對象 XMLHttpRequest
的實例而後咱們在上面的第二步接着深刻,用 get
和 set
對實例進行攔截,下面咱們重點看下這兩個方法裏作的事情。ajax
get(target, p, receiver)axios
get
攔截操做,代碼以下writable
,因此遇到這些屬性,咱們在以後的 set
操做裏,會將其緩存進帶有前綴 _
的同名屬性中,因此在 get
時,須要先判斷這些 _
前綴的屬性是否存在進而進行讀取,而 writable
屬性則經過 getter
函數進行讀取。result
,而後判斷 result
類型,若是是 true
,則終止方法。(這裏我加了一個功能,若是返回的是其餘 truthy
值如 object
或者 function
,能夠將 result
當作新的參數傳入。)set(target, p, value, receiver)瀏覽器
set
攔截操做,代碼以下catch
裏的代碼,此處就是上文說的對不是writable
的屬性進行的特殊操做。最後,只需將上述代碼生成的 Proxy 對象實例 賦值給 全局的 buit-in
對象 XMLHttpRequest
就大功告成了。 至此,基本上就是全部的代碼了,在這裏總結一下:
ajax-proxy
使用 Proxy
先對 buit-in
對象 XMLHttpRequest
的 new
操做進行攔截,而後再建立一個 Proxy
實例,對 buit-in
對象 XMLHttpRequest
實例的 get
和 set
進行攔截操做,最後將生成的 Proxy
對象實例 賦值給 全局的 buit-in
對象 XMLHttpRequest
,Done!
篇幅有限,有些細節沒有講清楚或者講的不對的地方請指出,更多的用法以及代碼請戳 →
GitHub: github.com/LazyDuke/aj…
repo 裏還有對 XMLHttpRequest
、JQuery
的 Ajax
模塊以及 axios
進行攔截的測試用例,以爲有意思的點一下 Star 吧~
本文章容許免費轉載,但請註明原做者及原文連接。