链接预取是不是跨子域工作?
Posted
技术标签:
【中文标题】链接预取是不是跨子域工作?【英文标题】:Does link prefetching work across subdomains?链接预取是否跨子域工作? 【发布时间】:2020-04-18 05:26:33 【问题描述】:我一直在尝试使用类似的方法来提高从简单着陆页点击到重量级单页应用时的性能:
<link rel="prefetch" href="https://example.com" as="document" />
<link rel="prefetch" href="https://example.com/app.js" as="script" />
<link rel="prefetch" href="https://example.com/app.css" as="style" />
当我的目标网页位于子域上时,它似乎没有明显的性能提升。说,https://subdomain.example.com
。
当我点击链接访问 https://example.com
时,我仍然在 Chrome 网络标签中看到很长的延迟,因为 app.js
和 app.css
已加载:
这是禁用预取的相同资源:
总共花费的时间大致相同。
使用预取缓存加载的资产之一的请求标头:
一般:
Request URL: https://example.com/css/app.bffe365a.css
Request Method: GET
Status Code: 200 (from prefetch cache)
Remote Address: 13.226.219.19:443
Referrer Policy: no-referrer-when-downgrade
回复:
accept-ranges: bytes
cache-control: max-age=31536000
content-encoding: gzip
content-length: 39682
content-type: text/css
date: Mon, 06 Jan 2020 21:42:53 GMT
etag: "d6f5135674904979a2dfa9dab1d2c440"
last-modified: Mon, 06 Jan 2020 20:46:46 GMT
server: AmazonS3
status: 200
via: 1.1 example.cloudfront.net (CloudFront)
x-amz-cf-id: dO3yiCoPErExrE2BLYbUJaVye32FIJXXxMdI4neDGzGX9a6gcCDumg==
x-amz-cf-pop: LAX50-C1
x-amz-id-2: 1O0LmihxpHIywEaMQWX7G3FDAzxtH9tZq1T/jeVLMzifFSJSIIJSS6+175H61kKdAq6iEbwfs2I=
x-amz-request-id: AF35C178092B65D4
x-cache: Hit from cloudfront
请求:
DNT: 1
Referer: https://example.com/auth/join
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (Khtml, like Gecko) Chrome/79.0.3945.117 Safari/537.36
我的问题是:如果 Chrome 指示使用了预取缓存,那么为什么会有很长的内容下载时间?
Chrome 似乎有不同种类的缓存:预取缓存、磁盘缓存和内存缓存。磁盘缓存和内存缓存非常快(5ms 和 0ms 加载时间)。然而,有时 300 毫秒的下载时间,预取缓存毫无用处。我能从技术上解释为什么会发生这种情况吗?这是 Chrome 的错误吗?我在 Chrome 79.0.3945.117 上。
【问题讨论】:
Prefetch 用于加速未来的导航,请参阅 (web.dev/link-prefetch) 的简要说明 是的,预取应该加快未来的导航。那为什么在我的情况下它没有加快速度呢?查看时序图。 您可以尝试将子域内容放在另一个域上,并检查是否也需要相同的时间来加载?您似乎已经得出子域可能是一个问题,而没有通过显示非子域(即其他域)案例的工作原理来展示它。如果子域是一个问题,那么下一步就是探索是否有 Chrome 配置设置可以调整,或者 或者子域和/或独立域的加载时间是否在其他具有类似工具集(如 Firefox Inspector 或 Opera)的浏览器上出现?如果您引用的其他使用不同引擎的浏览器(我不确定哪个会做哪些不再做)上出现相同的时间问题,那很可能是一个错误 - 我完全相信它可能是一个 Chrome 错误如果这些注明的时间值在其他浏览器上明显不同。 【参考方案1】:将<link rel=prefetch>
添加到网页会告诉浏览器下载用户将来可能需要的整个页面或部分资源(如脚本或 CSS 文件)。这可以改善诸如首次内容绘制和交互时间等指标,并且通常可以使后续导航看起来立即加载。
预取提示会为不需要的资源消耗额外的字节,因此需要慎重应用此技术;仅当您确信用户需要资源时才预取资源。考虑在用户连接速度较慢时不要预取。您可以使用 Network Information API 检测到这一点。
有多种方法可以确定要预取的链接。最简单的一种是预取当前页面上的第一个链接或前几个链接。还有一些库使用了更复杂的方法,本文稍后将对此进行解释-https://web.dev/link-prefetch/。
【讨论】:
我正在寻求解释为什么链接预取在我的特定情况下没有加快速度。是因为子域、服务人员还是其他原因?如果您查看我的屏幕截图,您可以看到尽管预取,浏览器仍会重新下载内容。【参考方案2】:我只能猜测。自信的答案可能只有您自己通过实验才能找到。有太多变数需要考虑。但这里有一些想法:
prefetch
是浏览器的提示。浏览器可以出于某些任意原因忽略它。不仅如此,它的优先级最低。
例如以防万一,请检查您的浏览器设置:Menu/Settings/Advanced/Privacy and security/Preload pages for faster browsing and searching
(或类似的东西)。
如果您使用移动互联网也可能是个问题。https://www.technipages.com/google-chrome-prefetch
从着陆页导航到example.com
的速度有多快?
检查您的服务器日志,看看它是否收到过prefetch
请求。
检查您的服务器是否设置了一些奇怪的标头来响应prefetch
请求。例如。 Cache-Control: no-cache
。是的,我看到你有cache-control: max-age=31536000
,所以如果服务器会为同一个请求发送不同的标头(嗯......几乎相同,至少你没有说是,至少可以有一些headers表明是prefetch
请求),但是奇怪的事情发生了。
您可能应该尝试添加crossorigin
属性。例如
<link rel="prefetch" href="https://example.com/app.css" as="style" crossorigin />
在这里https://www.w3.org/TR/resource-hints/你可以找到这个例子
<link rel="preconnect" href="//example.com">
<link rel="preconnect" href="//cdn.example.com" crossorigin>
与您的情况非常相关,但不幸的是没有解释。
在您的问题的原始版本中,您提到了服务人员...
如果他们下载了一些东西,甚至你自己手动下载了一些东西,这也可能是问题所在。因为prefetch
的优先级最低
https://developer.mozilla.org/en-US/docs/Web/HTTP/Link_prefetching_FAQ#What_if_I.27m_downloading_something_in_the_background.3F_Will_link_prefetching_compete_for_bandwidth.3F
如果您使用 Mozilla 下载内容,链接预取将延迟到任何后台下载完成
我认为 Chrome 也是如此。
您是否尝试将登录页面移至根域?如果是,并且prefetch
按预期工作,那么是的 - 子域是问题的原因。 GUI 消息Status Code: 200 (from prefetch cache)
可能只是一个小故障。因为就在最近,Chrome 中的 prefetch
行为开始发生一些变化。我还不知道事情是否解决了。基本上,是的,您有一定的概率只能来自同一来源的prefetch
。
https://docs.google.com/document/d/1bKGDIePAuF6YXmmrwM33LeLvtuCsla3vTspsxsNp-f8/edit
【讨论】:
阅读您的答案后的一些随机注释:我从登录页面导航到 example.com 的速度非常慢,因此有足够的时间加载所有资源。我在 Chrome 中禁用服务人员的情况下进行了上述测试。我认为 crossorigin 属性是为了别的。我确实尝试过使用它,但没有运气。最坏的情况是,我将通过将登录页面移动到根域来进行您建议的测试。我希望这里的答案可以节省我的工作。 你试过FF吗?来自上面的 MDN 链接:“Mozilla 会从不同的主机预取文档吗?是的。链接预取没有同源限制。将预取限制为仅来自同一服务器的 URL 不会提高浏览器的安全性。”这段话可能已经过时,但仍然如此。很高兴知道他们在 Chrome 上的行为是否有所不同。 我试过了,但我无法禁用似乎优先于预取缓存的服务工作者。不过我可以再试一次。 @Maros,不知何故你不拥有代码,或者有一些技术问题?【参考方案3】:你应该添加下面的代码,以防你是子域并且你想要来自域的资源
<link rel="preconnect" href="https://example.com">
【讨论】:
以上是关于链接预取是不是跨子域工作?的主要内容,如果未能解决你的问题,请参考以下文章
React/Express set-cookie 不能跨不同的子域工作
跨子域的 Ajax jquery - 带有 403 禁止错误的 OPTIONS 请求