在使用以下代碼發起請求的時候,個別接口出現了沒法獲得結果的狀況。node
async function req() { const res = fetch(xxx); let resData = null; try { resData = await res.clone().json(); } catch (err) {} if (!resData) { log(await res.clone().text()); } }
我經過其餘請求工具,發現出問題的接口是正常響應的。也就是確認了問題是出在本身的代碼裏面的。json
我在 try 後面打斷點,想看一下 resData 收到的是什麼,發現程序根本走不到那,可是 try 裏面也沒有報錯。
到這一步,我就以爲問題有點奇怪了。緩存
我只能到 node-fetch 的代碼裏面去加斷點看一下是什麼狀況了。async
在這過程當中又出現了很詭異的一幕。我分別在 on('data')
和 on('end')
的時候加調試信息,發現 end
事件沒有觸發,但若是在 on('data')
中添加斷點的話,end
可以觸發,而整個請求也能收到響應結果了。工具
經過進一步調試,我發現若是不對 node stream 的模型作一個系統的瞭解,我可能會很難查出問題的緣由。但對於問題的解決,依稀記得以前使用 res.json()
的時候是沒有問題的。fetch
因而,我嘗試着將 res.clone().json()
改爲 res.json()
,果真問題不在出現,請求順利接收。這時候我開始懷疑是否是 node-fetch 在 clone 的實現上有 bug 。但看了看源碼,思路很清晰,感受不出哪有問題啊。因此,沒有了解清楚 stream 相關的思路前,還不能妄下定論。調試
而對於 .json
失敗後,須要記錄響應文本的狀況,就改用 res._convert().toString()
實現了。code
後來,我又經過一步一步斷點調試和對 stream 的文檔和源碼的查看,終於定位了問題。接口
原來,node-fetch 在 clone 的時候產生了兩個目標,源碼以下:事件
p1 = new PassThrough(); p2 = new PassThrough(); body.pipe(p1); body.pipe(p2); // set instance body to teed body and return the other teed body instance.body = p1; body = p2;
而後個人代碼使用了其中一個即 res.clone
的返回進行 .json
操做,至關於 p2.json()
。但對另外一個 res 即 p1 沒有作處理。
而 stream 有一個 back pressure 機制,由於 p1 沒有消耗,緩存數據滿時會使其源 pause,從而致使 p2 也不能結束。