link rel=preload能够与fetch一起使用吗?

20
我有一个大的JSON数据块希望在网页加载前预加载。为此,我在我的页面上添加了<link rel="preload" as="fetch" href="/blob.json">代码。我也有一个JS请求来获取相同的JSON数据。
但这并不起作用,控制台报告:

[警告] 资源blob.json已经使用preload链接进行预加载,但没有在窗口加载事件后的几秒钟内使用。请确保它不是无谓地预加载。

MDN声称可以通过在链接标记中添加crossorigin来解决此问题。据我所知,这并不正确,任何跨域属性的组合都不能使其正常工作。
使用开发者控制台的copy-as-curl命令,似乎没有任何链接标记和属性的组合会像JS的fetch/XHR调用一样发出相同的请求。
我很想错了。
3个回答

23

这是一种适用于Chrome和Safari、同时支持cookie的预加载fetch的解决方案。

不幸的是,它只适用于相同域的请求。

首先,不要为预加载标签指定crossorigin属性,这将确保Safari以no-cors模式发送请求并包含cookie。

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

第二,Fetch API 请求应该在no-cors模式下进行,并包括凭据(cookies)。 请注意,此请求不能有任何自定义标头(如AcceptContent-Type等),否则浏览器将无法将此请求与预加载的请求匹配。

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

我尝试了其他的crossorigin属性值和fetch API配置组合,但在Safari中都没有生效(只有在Chrome中有效)。

这是我尝试过的内容:

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

<script>
fetch('/data.json', {
    method: 'GET',
    credentials: 'same-origin',
    mode: 'cors',
})
</script>

在Chrome中可以正常工作,但在Safari中无法正常工作,这是因为在Safari中预加载请求不会发送cookie。

<link rel="preload" as="fetch" href="/data.json" crossorigin="use-credentials">

<script>
fetch('/data.json', {
    method: 'GET',
    credentials: 'include',
    mode: 'cors',
})
</script>

在Chrome中可以正常运行,但在Safari中无法正常运行。虽然预加载请求发送了Cookie,但Safari无法将fetch与预加载请求匹配,可能是因为不同的cors模式。


为什么这个没有更多的赞?!我猜其他人都没有预取JSON ¯_(ツ)_/¯ - nameofname

3

感谢在此错误中的讨论,我成功地在Chromium 67中使用fetchpreload工作:

首先,在预加载链接中添加crossorigin属性:

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

其次,将同源凭据添加到fetch请求中:

fetch(url, {credentials: 'same-origin'}).then(response => {
    console.log(response);
});

或者,您可以使用XMLHttpRequest代替fetch(使用XHR时不需要添加任何内容),但仅当您不打算使用responseType = 'blob'时才能使用 - 它由于另一个错误而无法工作。


1
如果/blob.json需要cookies,这种方法在Safari中不起作用。在此处,我发布了一个带有一些解释的工作示例https://dev59.com/bFQK5IYBdhLWcg3wBrQK#63814972 - Eugene Fidelin

1

看起来这是Safari和Chrome之间的差异。Safari会将警告发布到控制台,但Chrome不会,因此可能将crossorigin添加到链接元素确实解决了问题,但Safari存在某种错误?


你成功让它工作了吗?我看到Chrome发出了3个请求,而不仅仅是预加载一个 - 这正是我想要实现的。 - mkhatib
1
是的。目前我只看到一个请求 https://homicides.news.baltimoresun.com/ 上的 JSON 文件。 - Carl
3
对于未来的网络探险家,该标签为<link rel="preload" as="fetch" href="/baltimore-homicides-victims-1543614381.json" id="victims-url" crossorigin>,而JS仅为一个XMLHttpRequest - Carl
2
这在Chrome中可以工作,但在Safari 12.0.3中仍然无法工作。我在https://homicides.news.baltimoresun.com/上看到了两个预加载的JSON资源请求和控制台警告:“使用链接预加载预加载了https://homicides.news.baltimoresun.com/baltimore-homicides-victims-1549998951.json资源,但在窗口加载事件后的几秒钟内未被使用。请确保它不是为了无用而预加载。” - dysfunction

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