HTML - 为什么预加载的资源会再次加载?

7

这是我的示例代码:

  <body>
    <link rel="preload" href="/fonts/Roboto-Regular.woff2" as="font" />
    <style>
      @font-face {
        font-family: "Roboto";
        src: url("/fonts/Roboto-Regular.woff2") format("woff2");
      }
      * {
        font-family: "Roboto", sans-serif;
      }
    </style>

    <section>
      <h2>Hello World</h2>
    </section>
  </body>

期望:

Roboto-Regular.woff2 应只被下载一次。第二次访问应在<5ms内完成,因为它是从缓存中读取的。

实际情况:

Roboto-Regular.woff2 被完全下载了两次。第二次访问所需时间与第一次相同。

Hard Refresh Waterfall

这里的蓝色条是 Content Download

我尝试过的方法:

在这里提出的解决方案:preloaded images get loaded again。但我很快意识到我的问题与缓存无关。如下图所示,在文件的响应标头中已经配置了服务器端的缓存控制:

Response Header

上一个瀑布截图是在强制刷新 (ctrl F5) 后截取的;这个是在软刷新后截取的:

Soft Refresh Waterfall

这次两个请求都只是从缓存中获取它们的响应,这表明缓存与整个情况无关。

那么问题出在哪里呢?

我的环境:

Windows 10 Pro N 1909

Google Chrome 78.0.3904.108 x64


1
你为什么要再次声明字体? - Aslam
我只是以Roboto作为例子。在部署中,我有自定义的字体文件。 - cyqsimon
3个回答

10

原来与CORS有关。

今天我偶然发现了答案,当我注意到控制台中出现了几个之前不存在的新警告时。

New warnings

这些警告基本上准确地描述了我的问题。我进行了快速的谷歌搜索,最终找到了使用rel="preload"预加载内容,其中提到:

即使获取不是跨域的,一个有趣的情况也适用于字体文件。由于各种原因,这些必须使用匿名模式CORS进行获取。

根据建议,我只需在我的预加载声明中添加crossorigin

<link rel="preload" href="/fonts/Roboto-Regular.woff2" as="font" crossorigin />

然后我的预加载就可以工作了。

Preload Working


另外

如果您正在预加载MIME类型为fetch的资源,例如.json,出于类似的原因(我假设),您还需要在预加载声明中包含crossorigin属性(参考)。

fetch requires crossorigin too


3

对于下一个到达这里的人:

如果您遇到相同的问题(资产重复下载),但已经设置了 crossorigin 属性。

<link rel="preload" href="/fonts/Roboto-Regular.woff2" as="font" crossorigin />

您真的要跨域请求资源吗?

尝试删除它!

<link rel="preload" href="/fonts/Roboto-Regular.woff2" as="font" />

我们需要为字体文件添加crossorigin,即使它们在相同的源上,是吗?正如接受的答案中所提到的。 - gaurav5430

-1
打开开发者工具时,Chrome会禁用缓存,这可能导致资源重新加载。在菜单栏中取消禁用缓存框上的复选标记通常可以解决此问题。

1
禁用缓存不会导致浏览器对同一资源发出两个请求。 - Vijay Purush
@VijayaraghavanPurush 在Chrome中绝对可能发生。通常与js / lazy loading结合使用。我不知道为什么,但这是一个常见问题,并且可以重现。 - eisbehr

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接