8

假设我们有几个不同的网站:website1.com、website2.com、website3.com。我们在所有这些上都使用 jQuery,并从 CDN 中包含它,例如 googleapis.com。浏览器的预期行为是将其缓存一次并将其用于所有其他网站。Chrome 似乎可以这样做,但 Safari 会为每个域下载 jQuery。

例子

  1. 使用下面给定的 JS 代码,在 Chrome中打开nytimes.combbc.comdw.de。
  2. 在第一个网站上附加 jQuery,然后查看 DevTools 的 Network 选项卡。它会说它得到了 jQuery。
  3. 现在打开任何其他网站并再次附加 jQuery - 答案将是“来自缓存”。

但是,Safari 会说它正在为每个域加载 jQuery,但尝试打开其中一个域上的任何网页并再次附加脚本 - 你会看到现在它说它从缓存中获取了 jQuery。所以看起来它缓存了一个域的数据,即使它已经从另一个域的确切 URL 下载了资源。

这个假设是否正确,如果正确,如何解决?

您可以复制/粘贴的代码:

setTimeout(function() {
    var SCRIPT_SRC = '//ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js';

    var s = document.createElement('script');
    s.type = 'text/javascript';
    s.async = true;
    s.src = SCRIPT_SRC;
    var x = document.getElementsByTagName('script')[0];
    x.parentNode.insertBefore(s, x);
}, 0);

UPD:使用静态图像对其进行了测试。

test.com、test2.com 和 test3.com 有<img src="http://image.com/image.jpg" />. 在除 Safari 之外的所有浏览器中,访问日志仅显示一个(第一个)对图像的请求。Safari 获取每个新域(但不是子域)的图像。

4

4 回答 4

6

我也注意到了这一点,我怀疑这是出于隐私原因。

默认情况下,Safari 会阻止第三方 cookie。第三方 cookie 是b.com为 请求的资源设置的 cookie a.com。例如,这可用于跨域跟踪人员。您可以有一个b.coma.com和请求的脚本c.comb.com可以基于第三方 cookie 将唯一的客户端 ID 插入到此脚本中,以便a.com并且c.com可以跟踪这是同一个人。

Safari 会阻止此行为。如果b.com为 请求的资源设置 cookie a.com,Safari 会将该 cookie 装箱,以便仅b.com在 更多请求时将其发送给a.com。它不会被发送到b.com请求c.com

现在输入缓存,特别是Etag标题。AnEtag是一个任意字符串(通常是文件的哈希),可用于确定自该人上次请求以来所请求的资源是否已更改。这通常是一件好事。如果没有更改,它会保存重新发送整个文件。

但是,因为 anEtag任意字符串,b.com所以可以将其设置为包含客户端 ID。这称为Etag 跟踪。它允许以与 cookie 几乎完全相同的方式跨域跟踪一个人。


摘要:通过不跨域共享缓存,Safari 可以保护您免受跨域 Etag 跟踪。

于 2016-05-04T03:24:59.030 回答
1

这是设计使然,Safari 团队称之为智能跟踪保护 - https://webkit.org/blog/7675/intelligent-tracking-prevention/ - 缓存是基于文档来源和第三方来源的双键

基于使用 HTTP 存档数据的研究和 Yahoo / Facebook 关于缓存寿命的研究,我怀疑 jQuery 等的共享缓存是否有效 - 没有足够多的站点使用相同版本的库,并且这些库不会在缓存中存在很长时间– 因此 Safari 的行为有助于防止跟踪,同时不会真正影响性能

于 2018-09-11T10:15:47.690 回答
0

您可以尝试使用 XMLHTTPRequest,而不是简单地添加 DOM 元素。它允许您定义自定义标题 - 其中之一是Cache-Control.

试一试,它应该覆盖浏览器级别发生的任何事情:

(function () {

    var newRequest = function() {
        return (window.XMLHttpRequest) ? new XMLHttpRequest() : new ActiveXObject( 'MsXml2.XmlHttp' );
    }

    var loadScript = function(url) {

        var http = new newRequest();

        http.onReadyStateChange = function() {
            if (http.readyState === 4) {
                if (http.status === 200 || http.status === 304) {
                    appendToPage(http.responseText);
                }
            }
        }

        // This is where you set your cache
        http.setRequestHeader( 'Cache-Control', 'max-age=0' )// <-- change this to a value larger than 0

        http.open('GET', url, true);
        http.send(null);
    }

    var appendToPage = function(source) {

        if (source === null) return false;

        var head = document.getElementsByTagName('head')[0];

        var script = document.createElement('script');
            script.language = 'javascript';
            script.type  = 'text/javascript';
            script.defer = true;
            script.text  = source;

        head.appendChild(script);
    }

    loadScript( '//ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js' );
})();

注意:Safari 过去曾遇到过一些缓存问题。然而,据我了解,这主要是关于提供陈旧的内容——而不是相反。

于 2014-07-17T06:55:58.617 回答
-1

这里有一些建议:

  1. 您是否检查过“禁用缓存”选项是否已禁用?
  2. 您是否在网络开发面板中寻找 HTTP 状态代码?
  3. 您是否尝试过使用WireShark等工具捕获流量?

此致。

于 2016-01-05T01:58:12.167 回答