如何調試 node_modules 源碼?

前言

最近收到網友留言,在使用 Mock:Intercept and directly return data 插件時,接口成功被攔截,並且在 Console 中有打印。按照目前的邏輯,這是成功匹配到 Mock 接口的標識,但就是在代碼中獲取不到數據!

看到這裏,我的第一感覺是會不會配置的數據結構與真實的接口返回不一致。比如需要返回的數據結構是:

{
    "code": 0,
    "message""請求成功",
    "data"{
        "id": 1,
        "name""張三"
    }
}

而實際返回的數據結構是:

"data"{
    "id": 1,
    "name""張三"
}

會不會是少了一層包裝?或者數據的類型不對?Number 類型的寫成了 String 類型?

所以建議查看數據結構是否正確。

直到這兩天參與到另外一個項目開發,該項目的接口請求使用的是 superagent 庫。這個的場景和網友評論的幾乎一樣,Console 中有打印 Mock 成功的接口,可以是頁面中就是不展示數據。

打印 Mock 接口

看到這裏,又深刻地體會到了一個道理:出現問題,先從自己身上找原因

在這裏,感謝提出問題的朋友!!!

好了,回到主題,之前的項目,使用 axios 一直沒問題,爲什麼使用 superagent 就會出現這個問題呢?

查找原因

查看代碼

if (err || (result.body && !result.body.success)) {
  // 異常報錯
  // ...
} else {
  res(!!result.body && result.body.data);
}

發現項目中使用的是接口返回的 body 字段。打印 XMLHttpRequest 的返回值,對比正確以及不正確有什麼不同。

正確的情況下,返回的 body 字段中是有值的。

正確的情況

錯誤的情況下,返回的 body 字段中沒有值。

錯誤的情況

前後的不同找到了,現在就可以來找原因了。

查找 body 是在哪裏被賦值的

剛纔通過 console.log 的方式打印了返回值,但確不方便知道這個返回值中的 body 值是在哪裏被賦值的。

通過 console.trace(result) 的方式進行打印。

console.trace() 不僅能打印出值,還能輸出調用棧信息。

打印截圖如下所示:

console.trace

在右邊可以看到在輸出日誌之前的一些調用棧。可以看到這裏經歷了 node_modulessuperagent 庫的 client.js 文件中的某個方法。

點擊 client.js:468 跳轉到對應的文件定義中。

468 行處打上斷點,然後刷新頁面,重新請求數據。

斷點

此時的 resbody 是有值的。

找到 res 的定義,打上斷點,重新刷新瀏覽器,發現這個 resResponse 實例的返回值。

res 來源

F11 或者直接點擊進入方法圖標,進入 Response 方法中。

進入 Response 方法

最後在 Response 方法中找到 body 是根據 getResponseHeader() 方法中返回的 content-type 值是不是 application/json 來處理的。如果 responseHeader 中的 content-type 中包含 application/json,就將返回的 text 字符串進行格式化,然後保存在 body 中,前端代碼中就直接使用 body 中解析好的 JSON 值了。

進入斷點的方法內

解決方法

通過上面的步驟,找到了問題出現的原因。但爲什麼 MockgetResponseHeader() 中獲取的 content-type 爲空呢?

正常情況下,接口返回時會指定 content-type: application/json;charset=UTF-8。而 Mock 插件在攔截接口請求後,直接就返回了 responseText

所以這裏,需要在 Mock 接口匹配成功後,再增加一下 getResponseHeader() 的返回值。

let getResponseHeader = ORIGIN_XHR.prototype.getResponseHeader;
NewXMLHttpRequest.prototype.getResponseHeader = function (headerName) {
const hasMockData = findMockResponse(this.requestURL, this.method);
// 如果 Mock 接口匹配成功,並且有請求 content-type 的值,就返回 application/json;charset=UTF-8 字符串
if (hasMockData && headerName && headerName.toLowerCase() === 'content-type') {
  return 'application/json;charset=UTF-8';
} else {
  getResponseHeader.apply(this, arguments);
}
};

經過以上修改,前面出現的問題就解決啦。

其它

本次的主要目的是找到 node_modules 包中出現問題的原因,node_modules 包並沒有問題。

如果是要修改第三方包,還可以通過 yarn linknpm link 的方式進行本地調試。

總結

調試 node_modules 包的小技巧爲:

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/IKSgtB2JtYX602JdiVag2g