为什么预加载链接不能用于JSON请求?

19

我的网站上的JavaScript加载了几个JSON来初始化自身。

我希望预先加载它们,这样当JavaScript在其上启动Ajax请求时,它们将立即加载。

一个新的link标签就是为此而存在的。

我尝试使用它来加载类似以下JSON的内容:

<link rel="preload" href="/test.json">

然而,Chrome似乎会加载两次,并在控制台中发出警告:

资源test.json使用link preload进行预加载,但在窗口加载事件后的几秒钟内未被使用。请确保它不是无用的预加载。

这样看来,预加载对于JSON文件似乎不起作用。 实际上,在规范中,我没有找到JSON的参考信息。

这是正确的吗,还是我做错了什么?


1
JSON不在规范中。您是否尝试过类似这样的代码:<link rel="preload" href="test.json" as="json" type="application/json" crossorigin>? - Asons
另外,请注意这仅适用于Chrome浏览器,其他浏览器不支持“preload”。 - Asons
我尝试了<link rel="preload" href="test.json" as="json">,但出现了错误消息,抱怨“as”值不正确。是的,我知道“preload”目前只适用于Chrome,但我也在使用“prefetch”来解决其他浏览器的同样问题。 - paulgreg
好的...我也会尝试使用 as="script" - Asons
显示剩余3条评论
9个回答

23
根据https://developer.mozilla.org/en-US/docs/Web/HTML/Preloading_content,JSON文件需要添加as="fetch"。 因此,您的代码应该是: <link rel="preload" href="/test.json" as="fetch"> 所有现代浏览器都支持它,如果资源在几秒钟内未使用,则会收到警告消息,因为这样“预加载”它是适得其反(延迟,双重加载等)。
这与<link rel="prefetch" ...>不同,后者是为了预测未来的导航,并且支持性不广泛。
有关此内容的Chrome Illustrated文章,请访问:https://medium.com/reloading/preload-prefetch-and-priorities-in-chrome-776165961bbf

11
如果您和我一样遇到同样的问题,那么您的响应可能会使用 Vary: Accept 发送,预加载请求是使用 Accept: */* 发送的,并且 fetch/xhr 请求是使用 Accept: application/json 进行的。
看起来预加载的 Accept: 行为无法更改(叹息),因此您要么需要删除 Vary: Accept,要么使用匹配的 Accept: 标头进行 fetch/xhr 请求。

1
我尝试在加载JSON时在ajax调用中设置Vary: */*,但Chrome给出了与之前相同的警告:“资源...使用链接预加载进行了预加载,但未在窗口的加载事件后的几秒钟内使用。请确保它不是无谓地预加载。” - paulgreg
我在这里报告了一个问题:https://bugs.chromium.org/p/chromium/issues/detail?id=962642 - Oleg Vaskevich
1
我遇到了同样的问题。在我的情况下,我使用的JS库用于XHR(plotly,它本身使用了旧版本的d3)添加了额外的“Accept”标头。从请求中删除“setRequestHeader”调用可以为我解决这个问题。 - Samuel Bierwagen

8

您需要添加的不仅是 as="fetch",还应该 (参考此评论) 添加 crossorigin="anonymous"。应该这样工作:

<link rel="preload" href="/test.json" as="fetch" crossorigin="anonymous">


3
发现在使用fetch API与rel=preload组合时,Chrome存在一个错误(链接)。我通过使用XMLHttpRequest解决了这个问题。
尽管在Chrome 62中似乎已经修复了这个问题,但是在我的Chrome 63上仍然可以重现这个问题。

它确实仍然是一个问题。 - Prisoner
我在这里添加了一个问题,我们将看看他们会说什么 https://bugs.chromium.org/p/chromium/issues/detail?id=850099 - Prisoner
有一个解决方法适用于fetch,感谢@Prisoner的错误报告发现。 - user
我仍然在使用XHR时遇到问题。仍然不确定我做错了什么。 - Jason

2

这是一种在Chrome和Safari中都有效的方法。

<link rel="preload" as="fetch" href="/data.json">

fetch('/data.json', {
    method: 'GET',
    credentials: 'include',
    mode: 'no-cors',
})

这个答案包含更多细节和解释,说明为什么以及如何工作https://dev59.com/bFQK5IYBdhLWcg3wBrQK#63814972


0

我尝试了很多 https://w3c.github.io/preload/#as-attribute 允许的值,但是唯一能够正常获取JSON数据的方法是完全删除 typeas 指令,让浏览器自行判断。在最新版Chrome中有效,但随着浏览器行为的改变,可能会发生变化。

Developer tools image showing XHR push


0
根据评论中提到的Chromebug,当你设置responseType = 'blob'时,preload不起作用。
解决方法是将responseType = 'arraybuffer',然后在onload中手动转换为blob,使用var blob = new Blob([xhr.response], {type: xhr.getResponseHeader("Content-Type")});

-3
尝试使用as="xhr"。当我进行服务器推送时,它在Chrome中似乎可以工作-虽然这与HTML标记不完全相同,但如果您通过Ajax / XmlHttpRequest获取资源,则可能会解决此问题。

2
使用 as="xhr" 会在控制台中发出警告: <link rel=preload> 必须具有有效的 as 值。 - paulgreg

-5
尝试使用as="object"。对我来说似乎有效:
<link rel="preload" href="/test.json" as="object">

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