摘要:前段時間重構一個頁面,頁面中存在通過第三方代碼插入的動態廣告正常的產品需求,上線后發現第三方的廣告資源存在重復請求的問題。所以,同一個請求會觸發兩次的原因頁面加載時渲染元素會觸發第一次請求,執行代碼導致重新渲染觸發第二次請求。
前段時間重構一個頁面,頁面中存在通過第三方JavaScript代碼插入的動態廣告(正常的產品需求),上線后發現第三方的廣告資源存在重復請求的問題。由于控制廣告插入的JavaScript代碼由第三方提供,我們只負責按照他們要求的方式引入即可,所以對JavaScript代碼內容并不了解,在這種情況下開始了艱難的排查過程。雖困難重重,但最終還是找到了原因,在此過程中有些收獲,現將排查過程抽象如下:
注:以下過程和截圖皆在Chrome瀏覽器中進行。
一、代碼代碼大意:頁面上先渲染3個iframe(目前頁面插入廣告仍然以iframe作為主要實現形式),然后在最后一個iframe后面追加一個p元素
二、現象 1.頁面:渲染正常 2.Network:存在重復的異常請求(Status是canceled) 三、排查過程 1.重復請求從何而來?既然是解決重復請求的問題,那么重復請求從何而來是我們要解決的第一問題。
由于請求是從第三方的JavaScript代碼中發出的,去讀第三方壓縮后的JavaScript代碼更像無頭蒼蠅。整個過程就像在圍城之外徘徊,心急如焚。后來靜下心來發現Chrome的devtools中一個很關鍵的排查助力神器:Network下的Initiator
此列是什么意思呢?通俗地說就是觸發請求的位置。
通過對比發現,同一個重復的請求發起的位置并不相同,以/iframe-1為例:
點擊第一個請求的Initiator,跳轉的位置(標黃位置):
點擊第二個請求的Initiator,跳轉的位置(標黃位置):
通過觀察可以發現,第一個/iframe-1請求是由于正常渲染iframe元素自動觸發的,第二個/iframe-1請求是在執行JavaScript代碼(作用拼接DOM節點)時觸發的,然而對于觸發第二個/iframe-1請求的那行JavaScript代碼,其真實意圖僅僅是拼接一個p元素而已,并不期望其他額外的事情(比如觸發新的請求)發生。另外,對于/iframe-2和/iframe-3的第二次請求的觸發點都是那段拼接DOM節點的JavaScript代碼,至此,產生問題的罪魁禍首已經浮出水面,接下來我們分析下產生重復請求的原因。
2.為什么會重復請求?產生重復請求的JavaScript代碼
document.getElementById("container").innerHTML += "上面是iframe
";
翻譯成:
document.getElementById("container").innerHTML = document.getElementById("container").innerHTML + "上面是iframe
";
意思就明了多了:先獲取id為container的div元素的所有內部HTML,將其拼接p元素后,再賦值給container的innerHTML。
這個過程會導致iframe元素的重新渲染,也就會引發iframe對應的請求重新觸發。
所以,同一個請求會觸發兩次的原因:頁面加載時渲染iframe元素會觸發第一次請求,執行JavaScript代碼導致iframe重新渲染觸發第二次請求。
找到了問題的原因,解決問題的辦法也就水到渠成了,將
document.getElementById("container").innerHTML += "上面是iframe
";
改為:
var div = document.createElement("div"); var text = document.createTextNode("廣告"); div.appendChild(text); document.getElementById("container").appendChild(div);
問題解決了,不過,還有一個疑問:為什么渲染iframe產生的第一個請求的狀態是canceled?
3.為什么重復的請求的Status是canceled?首先Status是canceled代表什么意思呢?
從其字面意思理解,代表此請求被取消了,即此請求在發給服務器端之前就被瀏覽器取消了,也就是說此請求根本就沒有從瀏覽器發出去,更不可能到達服務器,所以狀態是canceled而不是HTTP狀態碼也就不難理解了。
那第一次的請求為什么會被瀏覽器取消呢?
用關鍵詞“chrome cancel request”谷歌了一下,在stack overflow上找到了一個比較全面的解答,截圖如下:
其中紅色標注即為我們要尋找的答案。
根據截圖大概梳理一下,Chrome瀏覽器會取消請求的幾種場景:
觸發請求的DOM元素被刪除了(比如img元素還沒有加載完就被刪除了)
做了一些不必要的數據加載(比如開始加載iframe后改變其src或重寫其內容)
大量的請求指向同一個服務器,并且前面請求的網絡問題表明后續的請求也走不通(DNS查詢錯誤,前面的請求報400)
至此,整個過程中的疑問點一一解開了。
四、總結現在再回顧此bug,產生的原因并不高深,但整個排查過程確實值得總結。小結一下:
1.對于第三方庫報錯,切莫妄圖通過通讀并熟悉整個庫后解決問題,通讀代碼只會浪費解決問題的時間,弄明白調用關系才是王道
2.Chrome開發者工具中的Network > Initiator代表請求是從哪里觸發的,對于定位請求非常有用,尤其是對于一些第三方庫中發出的請求
3.請求狀態為canceled,表示請求被瀏覽器取消了,并沒有從瀏覽器發出去,更不可能進到服務器
4.Chrome瀏覽器取消請求的幾種情景,見上圖
5.element.innerHTML += HTMLStr 表示將原有的子節點和新的節點拼接后再重新賦值,會導致節點元素重新渲染,節點內容中含有iframe時慎用
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/53125.html
摘要:前段時間重構一個頁面,頁面中存在通過第三方代碼插入的動態廣告正常的產品需求,上線后發現第三方的廣告資源存在重復請求的問題。所以,同一個請求會觸發兩次的原因頁面加載時渲染元素會觸發第一次請求,執行代碼導致重新渲染觸發第二次請求。 前段時間重構一個頁面,頁面中存在通過第三方JavaScript代碼插入的動態廣告(正常的產品需求),上線后發現第三方的廣告資源存在重復請求的問題。由于控制廣告插...
摘要:盡可能地將數據寫入,例如創建設置的都會將數據立即的寫入再來看看文檔怎么描述的看看這可愛的默認值我們終于知道了當我們不做任何設置時,默認采用的是方式顯而易見,使用方式能最大限度的減少與的交互,而在大多數場景下都是沒有問題的。 0.問題背景 此次問題源于一次挺嚴重的生產事故:客戶的訂單被重復生成了,而出問題的代碼其實很簡單: // .... redisLockUtil.lock(membe...
摘要:為了一探究竟,于是開啟了這次應用性能調優之旅。使用即時編譯器和都能輕輕松松的讓你的應用程序在不用做任何修改的情況下,直接提高或者更高的性能。 這是一份事后的總結。在經歷了調優過程踩的很多坑之后,我們最終完善并實施了初步的性能測試方案,通過真實的測試數據歸納出了 Laravel 開發過程中的一些實踐技巧。 0x00 源起 最近有同事反饋 Laravel 寫的應用程序響應有點慢、20幾個并...
閱讀 3686·2021-09-07 10:19
閱讀 3627·2021-09-03 10:42
閱讀 3584·2021-09-03 10:28
閱讀 2548·2019-08-29 14:11
閱讀 809·2019-08-29 13:54
閱讀 1594·2019-08-29 12:14
閱讀 417·2019-08-26 12:12
閱讀 3614·2019-08-26 10:45