link rel=preload 可以与 fetch 一起使用吗?

问题描述 投票:0回答:4

我有一个大的 JSON blob,我想在我的网页中预加载。为此,我已将

<link rel="preload" as="fetch" href="/blob.json">
添加到我的页面。我也有一个 JS 请求来获取相同的 blob。

这不起作用,控制台报告:

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

MDN 声称可以通过在链接标签中添加

crossorigin
来解决此问题。 AFAICT,这不是真的,任何组合或跨域属性都不会真正使其发挥作用。

使用开发人员控制台中的 copy-as-curl 命令,似乎没有链接标记加属性的组合可以发出与 JS 中的 fetch/XHR 调用相同的请求。

我很乐意在这一点上犯错。

fetch preload
4个回答
25
投票

这里是预加载提取的工作解决方案,它可以在 Chrome 和 Safari 中运行并支持 cookie。

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

首先,不要为预加载标签指定

crossorigin
属性,这将确保Safari将以
no-cors
模式发送请求并包含cookie

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

其次,fetch api 请求也应该在

no-cors
模式下完成并包含凭据(cookie)。 请注意,此请求不能有任何自定义标头(如
Accept
Content-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 模式不同。


3
投票

感谢这个 bug 中的讨论,我让

fetch
可以在 Chromium 67 中与
preload
一起工作:

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

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

其次,将同源凭证添加到获取请求中:

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

或者,您可以使用

XMLHttpRequest
代替
fetch
(使用 XHR,您不需要向请求添加任何内容),但前提是您不打算使用
responseType = 'blob'
- 它不会工作,因为另一个错误


1
投票

看起来这是 Safari 和 Chrome 之间的区别。 Safari 将警告发布到控制台,但 Chrome 没有,所以也许向链接元素添加

crossorigin
确实可以解决问题,但 Safari 有某种错误?


0
投票

添加尤金上面的答案(我将其添加为评论,但缺乏声誉)。

此案例适用于 Safari 中的跨域请求(但不适用于 Chrome)。

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

<script>
fetch('https://someotherorigin.com/data.json', {
    method: 'GET',
    credentials: 'omit',
    mode: 'cors',
})
</script>
© www.soinside.com 2019 - 2024. All rights reserved.