当前位置: 首页 > Web前端 > HTML5

查看重复页面请求的经验

时间:2023-04-05 20:24:59 HTML5

前段时间重构了一个页面,页面中有通过第三方JavaScript代码插入的动态广告(正常产品需求)。上线后发现第三方广告资源有重复请求。由于控制广告插入的JavaScript代码由第三方提供,我们只负责按他们要求的方式引入,所以我们不知道JavaScript代码的内容。在这种情况下,我们开始了艰难的调查过程。虽然困难重重,但最终还是找到了原因,过程中也有一些收获。现将排查过程抽象如下:注:以下过程及截图均在Chrome浏览器中进行。1.代码

代码大纲:先在页面渲染3个iframe(目前在页面插播广告还是以iframe为主要实现形式),然后在最后一个iframe后添加一个p元素2.现象1。页面:渲染正常2、网络:有重复的异常请求(状态为取消)三、故障处理流程1、重复的请求来自哪里?既然是解决重复请求的问题,那么重复请求从哪里来就是我们首先要解决的问题。由于请求是第三方JavaScript代码发出的,读取第三方压缩后的JavaScript代码更像是无头鸡。整个过程就像在围城外徘徊,焦急万分。后来静下心来,在Chrome的devtools中发现了一个很重要的排查神器:Network下的Initiator一栏是什么意思?通俗地说,就是触发请求的位置。通过对比,发现同一个重复请求的位置是不一样的。以/iframe-1为例:点击第一个请求的Initiator,跳转位置(黄色位置):点击第二个请求的Initiator,跳转位置(黄色标注位置):通过观察可以发现第一个/iframe-1请求是iframe元素正常渲染自动触发的,第二个/iframe-1请求是执行JavaScript代码(拼接DOM节点的功能),但是对于触发第二个/iframe-1请求,它的真正意图只是拼接一个p元素,并没有期望发生其他额外的事情(比如触发一个新的请求)。另外,第二次请求/iframe-2和/iframe-3的触发点是拼接DOM节点的JavaScript代码。至此,问题的罪魁祸首已经浮出水面。接下来我们分析一下重复请求的原因。2、为什么会重复请求?生成重复请求的JavaScript代码document.getElementById('container').innerHTML+='

上面是一个iframe

';翻译成:document.getElementById('container').innerHTML=document.getElementById('container').innerHTML+'

上面是一个iframe

';意思就清楚多了:先获取id为容器的div元素的所有内部HTML,拼接给p元素,然后赋值给容器innerHTML。这个过程会导致iframe元素的重新渲染,也会导致iframe对应的请求重新触发。所以,同一个请求之所以被触发两次:页面加载时渲染iframe元素触发第一次请求,执行JavaScript代码导致iframe重新渲染触发第二次请求。找到了问题的原因,问题的解决也就自然而然了。更改document.getElementById('container').innerHTML+='

上面是一个iframe

';to:vardiv=document.createElement('div');vartext=document.createTextNode('advertising');div.appendChild(text);document.getElementById('container').appendChild(div);问题解决了,但是还有一个疑问:为什么渲染iframe生成的第一个请求的状态是取消的?3、为什么重复请求的Status被取消了?首先,Status是什么意思取消?从它的字面意思来看,就是请求被取消了,也就是请求在发送到服务器之前就被浏览器取消了,也就是说请求根本就不是从浏览器发出的,更谈不上到达服务器,所以状态被取消而不是HTTP状态码就不难理解了。为什么第一个请求被浏览器取消了?用谷歌搜索关键字“chromecancelrequest”,在stackoverflow上找到了更全面的答案。截图如下:红色标记处就是我们要找的答案。根据截图,Chrome浏览器会取消请求的场景有几种:触发请求的DOM元素被删除(例如img元素在加载前被删除),一些不必要的数据加载完成(比如开始加载改变它的src或者在iframe之后重写它的内容)大量请求指向同一个服务器,前一个请求的网络问题导致后面的请求无法通过(DNS查询错误,previousrequestreported400)至此,整个疑惑一一解开。4.小结现在回过头来看这个bug,成因并不深刻,但整个排查过程确实值得总结。总结一下:1.对于第三方库的错误,不要试图通过通读和熟悉整个库来解决问题。通读代码只会浪费解决问题的时间,理解调用关系才是王道。2、ChromeDeveloperTools中的Network>Initiator代表请求是从哪里触发的,这对于定位请求非常有用,特别是一些第三方库发送的请求。3、请求状态为取消,表示请求被浏览器取消,不是浏览器发出的。更无法进入服务器4.Chrome浏览器取消请求的几种场景,见上图5.element.innerHTML+=HTMLStr表示原子节点和新节点拼接后重新赋值,会导致节点元素重新渲染,节点内容包含iframe时慎用