为什么重复的GET请求变慢了?

作者 : 开心源码 本文共2569个字,预计阅读时间需要7分钟 发布时间: 2022-05-12 共123人阅读

最近在研究慢请求监控的问题,写了一个简单的测试代码:在网页端(index.html)通过fetch函数向服务端获取数据,而后打印请求耗时。

function requestData() {    let start = new Date();    fetch("http://localhost:3000/company/basic")        .then(res => {            return res.json();        })        .then(res => {            let span = new Date() - start;            console.log("span:", span);        });}requestData();

在服务端通过setTimeout延时1500s才返回数据(服务端使用ExpressJS)。

app.get("/company/basic", (req, res) => {    setTimeout(function() {        res.send({ hello: "Hello Fundebug!" });    }, 1500);});

不出所料,span数据都稍微大于 1500。

然后,我突发奇想,假设我同时发送多个请求会怎样样呢?于是有了如下代码:

[1, 2, 3].forEach(function() {    requestData();});

结果如同也没问题,在 Chrome 浏览器下面是这个效果:

接入 Fundebug 慢请求监控测试

于是愉快地接入 Fundebug 监控:

<script    src="https://js.fundebug.cn/fundebug.1.9.0.min.js"    apikey="API-KEY"></script>

并设置假如请求时长超过 2 秒就上报:

if ("fundebug" in window) {    fundebug.httpTimeout = 2000;}

本以为刷新页面,应该不会收到报错。

结果,万万没想到的是,Fundebug 收到 2 个慢请求报错。

这不科学啊!

点开错误介绍,可以看到具体的报错信息。一个请求耗时 3018 毫秒,一个请求耗时 4525 毫秒。

也就是说,第一个请求没问题,假设是 1500 毫秒。我们把三个请求的时间放一起看看有何规律:1500,3018,4524。他们近似成等差数列,相差 1500 毫秒。于是,我怀疑三个请求是一个一个阻塞式的,而不是并发的。

测试并发请求不同 API 的情况

为了验证这一点,我将测试改为请求三个不同的 API 接口。

服务端代码:

app.get("/company/basic", resp);app.get("/company/basic1", resp);app.get("/company/basic2", resp);function resp(req, res) {    setTimeout(function() {        res.send({ hello: "Hello Fundebug!" });    }, 1500);}

网页端代码(requestData函数传入请求的 URL):

[    "http://localhost:3000/company/basic",    "http://localhost:3000/company/basic1",    "http://localhost:3000/company/basic2"].forEach(function(item) {    requestData(item);});

为了获取请求数据,将httpTimeout改为 1500。

if ("fundebug" in window) {    fundebug.httpTimeout = 1500;}

Fundebug 捕获三个请求的时间,分别为 1526,1525,1529。

至此大体验证了刚刚的假设:对同一个 API 接口的并发请求会被阻塞,对不同的 API 接口并发请求正常执行。

那么为什么会被阻塞呢?用意何在?接下来慢慢给各位详情。

背后的起因

在StackOverflow上找到了答案:

Yes, this behavior is due to Chrome locking the cache and waiting to see the result of one request before requesting the same resource again. The answer is to find a way to make the requests unique.

也就是说,Chrome 特意做了这样的设计。对于连续的相同请求,Chrome 会阻塞后面的请求,直到前面的完成。通过判断前面的请求返回的 Header 里面的缓存设置来决定下一步的行动。

我们可以做个试验来验证一下。

缓存试验

  • 服务端设置缓存 2 秒

    在服务端的接口返回代码中配置缓存时间

    res.setHeader("Cache-Control", "public, max-age=2");

  • 服务端设置不缓存

    res.setHeader(    "Cache-Control",    "private, no-cache, no-store, must-revalidate");

  • Chrome 开发者面板设置Disable Cache

最后的疑问

为什么打开和不打开谷歌开发者控制台,行为会不一样了?

其实是有起因的,而且这个干扰项一度成功阻止了我发现问题的本质。当我们在开发前台项目的时候,代码的改动希望能够实时地反应到网页上,而不是受到浏览器缓存的影响,但是我们发现往往刷新页面的时候没有真的去服务端获取数据,还是老的信息。于是,我们会去配置一个选项,将Disable Cache设置为true。也就是说,在开发环境下,缓存是被禁用了的,也就不存在等待第一个请求返回而后判断其 Header 里面Cache-Control设置的问题。这也是为什么打开谷歌开发者控制台,请求没有等待,立即执行了。

关于Fundebug

Fundebug专注于JavaScript、微信小程序、微信小游戏、支付宝小程序、React Native、Node.js和Java线上应用实时BUG监控。 自从2016年双十一正式上线,Fundebug累计解决了10亿+错误事件,付费用户有阳光保险、核桃编程、荔枝FM、掌门1对1、微脉、青团社等众多品牌企业。欢迎大家免费试用!

版权公告

转载时请注明作者 Fundebug以及本文地址:
https://blog.fundebug.com/2019/07/17/chrome-stall-multiple-same-request/

说明
1. 本站所有资源来源于用户上传和网络,如有侵权请邮件联系站长!
2. 分享目的仅供大家学习和交流,您必须在下载后24小时内删除!
3. 不得使用于非法商业用途,不得违反国家法律。否则后果自负!
4. 本站提供的源码、模板、插件等等其他资源,都不包含技术服务请大家谅解!
5. 如有链接无法下载、失效或广告,请联系管理员处理!
6. 本站资源售价只是摆设,本站源码仅提供给会员学习使用!
7. 如遇到加密压缩包,请使用360解压,如遇到无法解压的请联系管理员
开心源码网 » 为什么重复的GET请求变慢了?

发表回复