hello~親愛的看官老爺們你們好~最近接手維護公司另外一個 Node
項目,稍微熟悉一下代碼後,便被提了一個解決線上 bug 的需求。定位問題後解決仍是十分容易的,可是這個過程十分有趣,bug 出現的緣由也值得深思。於是有了這篇文章,分享此次 bug fixes 的過程。ios
項目是搜索相關的,頁端發請求到 Node
端,Node
包裝搜索請求參數後轉發 Java
,Java
返回數據後,Node
將數據組裝成 HTML
文檔返回給頁端。整個過程很是常規,但 Bug 出現的位置就十分奇妙了,線上偶現渲染出來的 HTML
文檔中部分 a
標籤連接指向了錯誤但有意義的地址。簡單的代碼以下:axios
const axios = require('axios');
const _arr = [
//數組內是一個個對象,保存着一些公用的數據
];
router.get('/test', (req, res) => {
axios(
//請求 Java 的各類配置
)
.then(response => {
//對 response 進行處理,省略若干步驟
for (let item of _arr) {
item.url = `?${querystring.stringify(response.url)}`;
}
})
.then(() => {
//其餘的異步操做
})
.then(data => {
res.render({
//...各類數據
_arr
})
})
})
module.exports = router;
複製代碼
若是對 Node
模塊機制比較熟悉的同窗,應該能看出問題的根源了。但若是是接手的項目,並且實際代碼比這個複雜 N 倍(項目中此接口大約有700行代碼),估計就沒那麼好分析了。數組
當時我接手時,在本地環境和測試環境,沒法復現出相同的問題。同時,被修改的連接實際上是從新搜索的連接,如以前搜索的是 123
,跳轉的連接正常來講仍是 123
的,但會變爲 xxx風景區
。於是一度認爲是有中間人進行攻擊,修改了模板中的連接。但分析的過程當中,發現兩個不合理的地方:閉包
Https
,修改修改協議後,線上環境仍偶現該問題。若是說第一點還情有可原的話,第二點基本就認定不是中間人的問題,除非中間人強到破解了加密或公司的私鑰泄密了。因而問題又回到了原點,代碼到底哪裏又出問題了呢?框架
線上環境是較難調試的,但能夠經過打日誌的方式進行分析。經過打點,發現請求 Java
後返回的 response.url
是正確的,但在渲染時 _arr
的 url
卻不一樣了,能夠肯定問題是出在 _arr
上,由於某些緣由,它的值被修改了。異步
定位到具體出現問題的地方後,緣由歸結起來就很簡單了,Node
中的模塊機制,實際上是經過函數包裝而成的,在此過程當中會造成閉包,簡略示例以下:函數
const module = {}; //全局變量
function(exports, require, module, __fileName, __dirname) {
const _arr = [];
module.exports = ....;
}
複製代碼
每一個文件都會被加工成上面代碼的形式,而 module
是全局可訪問的。並且須要記住一點,不是每次用到某個文件時,函數都會執行一次,而是隻要該文件被 require
一次後,它的相關代碼已經被記錄在全局的 module
中了。於是 _arr
是以單例的形式存在的,若是 exports
出去的代碼對 _arr
作了修改的話,會影響此後對 _arr
的讀取。好像有點繞,再簡單一點說,如一下 demo
:測試
function wrap() {
const arr = [];
return function() {
console.log(arr);
arr.push(1);
}
}
const module = wrap();
module(); //[]
module(); //[1]
module(); //[1, 1]
複製代碼
而項目的代碼有這麼一段:ui
for (let item of _arr) {
item.url = `?${querystring.stringify(response.url)}`;
}
複製代碼
這段代碼是有反作用的,它修改了 _arr
的內容,若是以後都是同步的代碼,那麼問題可能還不大(其實仍是有問題,但不會影響結果),但只要是異步的,那麼問題可能就會出現。知道了問題的根源,解決就很簡單了,要麼每次調用都從新定義 _arr
一次,要麼將代碼改成無反作用的~加密
以上就是整個 debug 過程的簡要描述,其實只是以前開發的同窗某些細節沒有考慮到,還好訪問量不大,但形成的後果不算特別嚴重。然而分析下來,發現這個 bug 是若干 Js
基礎問題共同做用而成的,當咱們不斷追求新技術、新框架的同時,是否是該靜下心來,好好鞏固一下語言的基礎呢?
感謝各位看官大人看到這裏,知易行難,但願本文對你有所幫助~謝謝!