为什么浏览器在这里低效地发出2个请求?

NoB*_*ugs 13 javascript ajax jquery http network-protocols

我注意到有关ajax和图像加载的奇怪之处.假设你在页面上有一个图像,并且ajax请求相同的图像 - 人们会猜测ajax请求会到达浏览器缓存,或者至少应该只发出一个请求,结果图像会转到页面和想要的脚本阅读/处理图像.

令人惊讶的是,我发现即使javascript等待整个页面加载,图像请求仍然会发出新请求!这是Firefox和Chrome中的已知错误,还是jQuery ajax正在做的坏事?

在这里你可以看到问题,打开Fiddler或Wireshark并在点击"run"之前将其设置为记录:

<script src="http://code.jquery.com/jquery-1.11.1.min.js"></script>
<div id="something" style="background-image:url(http://jsfiddle.net/img/logo-white.png);">Hello</div>
<script>

jQuery(function($) {
    $(window).load(function() {
        $.get('http://jsfiddle.net/img/logo-white.png');
    })
});

</script>
Run Code Online (Sandbox Code Playgroud)

请注意,在Firefox中,它会发出两个请求,这两个请求都会产生200-OK,并将整个图像发送回浏览器两次.在Chromium中,它至少在第二次请求时正确获取304,而不是两次下载整个内容.

奇怪的是,IE11下载整个图像两次,而IE9似乎积极地缓存它并下载一次.

理想情况下,我希望ajax根本不会发出第二个请求,因为它正在请求完全相同的URL.有没有理由在这种情况下css和ajax通常有不同的缓存,就好像浏览器使用不同的缓存存储来进行css vs ajax请求?

alg*_*thm 7

我使用最新的谷歌浏览器,它提出了一个请求.但是在你的JSFIDDLE例子中,你要加载jQuery两次.首先使用JSFIDDLE,然后使用脚本标记中的第二个代码.改进:JSFIDDLE

<div id="something" style="background-image:url('http://jsfiddle.net/img/logo-white.png');">Hello</div>

<script>
    jQuery(window).load(function() {
        jQuery.get('http://jsfiddle.net/img/logo-white.png');
    });

    // or

    jQuery(function($) {
        jQuery.get('http://jsfiddle.net/img/logo-white.png');
    });
</script>
Run Code Online (Sandbox Code Playgroud)

style当DOM准备好并且scriptDOM已准备好并且加载了每个图像和其他资源时调用.将两者放在一起嵌套是没有意义的,请参见:window.onload vs $(document).ready()

当然,图像在Web检查器的"网络"选项卡中加载两次.首先通过你的CSS,然后通过你的JavaScript.第二个请求可能是缓存的.

更新:但是此缓冲区中显示了是否缓存的每个请求.请参阅以下示例:http://jsfiddle.net/95mnf9rm/4/ 有5个缓存的AJAX调用请求,5个没有缓存.10个请求显示在"网络"标签中.当您在CSS中使用图像两次时,它只需要一次.但是如果您明确地进行了AJAX调用,那么浏览器会进行AJAX调用.如你所愿.也许它的缓存与否,但它是明确要求的,不是吗?

  • "当然,图像会在Web检查器的"网络"选项卡中加载.首先是通过CSS,然后是通过JavaScript." 提问者意识到这一点,这就是提出问题的原因.问题是为什么,因为没有立即显而易见的原因,浏览器应该加载相同的资源两次,因为它是从两个不同的上下文请求的.如果您说Google Chrome提出了一个请求,您是否可以解释它与您在Web Inspector中看到的内容之间的差异? (4认同)

m.e*_*roy 5

这个“问题”可能是CORS 飞行前测试

不久前我在我的应用程序中注意到了这一点,从单页应用程序检索信息的调用进行了两次调用。仅当您访问不同域上的 URL 时才会发生这种情况。就我而言,我们在与我们构建的应用程序不同的服务器(不同的域)上构建和使用 API。我注意到,当我在应用程序中对这些 RESTFUL API 使用 GET 或 POST 时,调用似乎进行了两次。

正在发生的事情称为飞行前https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS),向服务器发出初始请求以查看是否允许随后的调用。

摘自MDN:

与简单请求不同,“预检”请求首先通过 OPTIONS 方法向其他域上的资源发送 HTTP 请求,以确定实际请求是否可以安全发送。跨站点请求会像这样进行预检,因为它们可能会对用户数据产生影响。特别是,在以下情况下,请求会被预检:

  1. 它使用 GET、HEAD 或 POST 以外的方法。另外,如果 POST 用于发送 Content-Type 不是 application/x-www-form-urlencoded、multipart/form-data 或 text/plain 的请求数据,例如,如果 POST 请求向服务器发送 XML 有效负载使用 application/xml 或 text/xml,然后对请求进行预检。
  2. 它在请求中设置自定义标头(例如,请求使用 X-PINGOTHER 等标头)


NoB*_*ugs 1

Mozilla 的热心人士提供了一些关于为什么会发生这种情况的细节。显然,Firefox 假设“匿名”请求可能与正常请求不同,因此它会发出第二个请求,并且不会将具有不同标头的缓存值视为同一请求。

https://bugzilla.mozilla.org/show_bug.cgi?id=1075297