在 Web 性能领域需要吸收的知识的广度和深度真是令人难以置信。至少,我几乎每周都在发现新的东西。例如:Save-Data
标头,我是在 Google Developers 的一篇文章 中发现的,该文章由 Ilya Grigorik 撰写。
如果您想了解 Save-Data
的工作原理的简短版本,我乐意为您提供:如果您选择在 Chrome 的 Android 版本(或您桌面设备上的 数据节省扩展程序)中启用数据节省功能,Chrome 发送到服务器的每个请求都将包含一个值为 On
的 Save-Data
标头。然后,您可以根据此标头更改网站的内容传递方式,从而为用户节省数据。这是一个非常开放的机会,因此让我们探讨一些您可以根据 Save-Data
标头采取的措施,以减少网络传输的数据量!
更改图像传递策略
我不知道您是否注意到,图像通常是任何给定页面总负载量中最大的一部分。因此,使用 Save-Data
可以采取的最有效步骤可能是更改图像的传递方式。在我的博客中,我选择将高 DPI 图像的请求重写为低 DPI 图像。当我在我的网站上提供这样的图像集时,我使用 <picture>
元素来提供 WebP 图像,并使用 JPEG 或 PNG 作为后备,如下所示
<picture>
<source srcset="/img/george-and-susan-1x.webp 1x, /img/george-and-susan-2x.webp 2x">
<source srcset="/img/george-and-susan-1x.jpg 1x, /img/george-and-susan-2x.jpg 2x">
<img src="/img/george-and-susan-1x.jpg" alt="LET'S NOT GET CRAZY HERE" width="320" height="240">
</picture>
此解决方案由现代浏览器中内置的技术支持。<picture>
元素根据浏览器的功能提供最佳图像格式,而 srcset
将帮助浏览器确定哪种图像最适合任何给定设备的屏幕。不幸的是,<picture>
和 srcset
都无法控制要为希望节省数据的用户提供的哪个图像源。它们也不应该这样做!这不是 srcset
或 <picture>
的工作。
这就是 Save-Data
发挥作用的地方。当用户访问我的网站并发送 Save-Data
请求标头时,我使用 Apache 中的 mod_rewrite 来提供低 DPI 图像而不是高 DPI 图像
RewriteCond %{HTTP:Save-Data} =on [NC]
RewriteRule ^(.*)-2x.(png|jpe?g|webp)$ $1-1x.$2 [L]
如果您不熟悉 mod_rewrite,第一行是一个条件,它检查 Save-Data
标头是否存在以及是否包含值为 on
。[NC]
标志仅仅告诉 mod_rewrite 执行不区分大小写的匹配。如果满足条件,RewriteRule
将查找对以 -2x
(高 DPI 版本)结尾的 PNG、JPEG 或 WebP 资产的任何请求,并将此类请求重定向到以 -1x
(低 DPI 版本)结尾的资产。
现在是奇怪的部分:如果用户在启用数据节省功能的情况下访问,但随后将其关闭并在非计量(即 Wi-Fi)连接上返回,会发生什么情况?因为我们已经秘密地将对 -2x
图像的请求重写为 -1x
图像,所以浏览器将从浏览器缓存中提供低质量版本的图像,而不是从服务器请求高质量版本。在这种情况下,用户将被锁定在低质量体验中,直到他们清空浏览器缓存(或缓存条目过期)。
那么我们如何解决这个问题呢?答案在于 Vary
响应标头。Vary
指示浏览器如何以及是否应该使用缓存的资产,方法是将缓存条目与特定标头(s) 对齐。Vary
的值只是其他标头名称(例如,Accept-Encoding
、User-Agent
等)。如果我们希望浏览器根据 Save-Data
标头是否存在来缓存内容,我们只需将服务器配置为发送一个值为 Save-Data
的 Vary
响应标头,如下所示
<FilesMatch "\.(gif|png|jpe?g|webp)$">
Header set Vary "Save-Data"
</FilesMatch>
<FilesMatch "\.svg$">
Header set Vary "Accept-Encoding, Save-Data"
</FilesMatch>
在此示例中,我每次请求 GIF、PNG、JPEG 或 WebP 图像时都会发送一个值为 Save-Data
的 Vary
响应标头。对于 SVG,我发送一个值为 Accept-Encoding, Save-Data
的 Vary
标头。这样做的原因是 SVG 是可压缩的文本资产。因此,我希望确保浏览器(以及任何中间缓存,例如 CDN)在决定如何从缓存中检索条目时,除了 Save-Data
标头之外,还要考虑 Accept-Encoding
标头的值。

为此,我们现在有了一种图像传递策略,可以帮助用户节省数据,并且将使用不会在用户稍后关闭数据节省功能时保留的图像填充浏览器缓存。
当然,您还可以通过其他方式在 Save-Data
存在的情况下更改图像传递方式。例如,Cory Dowdy 撰写了一篇帖子,详细介绍了如何使用 Save-Data
来提供较低质量的图像。Save-Data
为您提供了很多空间来设计最适合您的网站或应用程序的图像传递策略。
选择退出服务器推送
服务器推送 是一款很棒的功能,如果您使用的是 HTTP/2 并且可以使用它。它允许您在客户端知道需要之前就将资产发送给他们。但是,问题是,在某些情况下,它可能出乎意料地不可预测。在我的网站上,我使用它来仅推送 CSS,这通常效果很好。但是,我确实在 Apache 中调整了我的推送策略,以避免出现问题的浏览器(即 Safari),如下所示
<If "%{HTTP_USER_AGENT} =~ /^(?=.*safari)(?!.*chrome).*/i">
Header add Link "</css/global.5aa545cb.css>; rel=preload; as=style; nopush"
</If>
<Else>
Header add Link "</css/global.5aa545cb.css>; rel=preload; as=style"
</Else>
在这种情况下,我说“嘿,我希望您预先将我网站的 CSS 推送到用户,但前提是他们没有使用 Safari。”即使 Safari 用户访问,他们仍然会收到 preload
资源提示(尽管带有 nopush
属性以阻止我的服务器推送任何内容)。
即便如此,在为启用了数据节省功能的用户推送资产时,我们也应该格外谨慎。在我的博客中,我决定不向任何启用了数据节省功能的用户推送任何内容。为此,我对初始 <If>
标头进行了以下更改
<If "%{HTTP:Save-Data} == 'on' || %{HTTP_USER_AGENT} =~ /^(?=.*safari)(?!.*chrome).*/i">
这与我的初始配置相同,但增加了一个条件,即“嘿,如果 Save-Data
存在并设置为 on
值,请不要推送该样式表。只需 preload
它即可。”这可能不是一个很大的变化,但它是一些可以帮助访客避免浪费数据的小事情,如果推送出于任何原因无效。
更改标记传递方式
使用 Save-Data
,您可以选择更改要传递的文档的哪些部分。这带来了各种机会,但在开始这项工作之前,您需要在后端语言中检查 Save-Data
标头。在 PHP 中,这样的检查可能如下所示
$saveData = (isset($_SERVER["HTTP_SAVE_DATA"]) && stristr($_SERVER["HTTP_SAVE_DATA"], "on") !== false) ? true : false;
在我的博客中,我在各种地方使用此 $saveData
布尔值来删除对给定页面内容不重要的图像的标记。例如,我的其中一篇文章 有些动画 GIF 和其他幽默图片,对于不介意的用户来说很有趣。但它们很重,并且对于传达文章的中心思想并不是真正必要的。我还删除了页眉插图和导航栏中我书籍的微型缩略图。

从有效负载的角度来看,这肯定会有深远的影响

另一个机会是使用前面提到的 $saveData
布尔值在 <html>
元素上放置一个 save-data
类
<html class="<?php if($saveData === true) : echo("save-data"); endif; ?>">
使用此类,我就可以编写样式来更改 background-image
属性中使用的资产,或任何引用外部资产的 CSS 属性。例如
/* Just a regular ol' background image */
body {
background-image: url("/images/bg.png");
}
/* A lower quality background image for users with Data Saver turned on */
.save-data body {
background-image: url("/images/bg-lowsrc.png");
}
标记不是您可以修改传递内容的唯一内容。您可以对视频执行相同的操作,或者执行一些简单的事情,例如每页提供较少的搜索结果。完全取决于您!
结论
Save-Data
标头为您提供了一个绝佳的机会,可以帮助那些请求您帮助他们节省数据的用户。您可以使用 URL 重写来更改媒体传递方式、更改标记传递方式,或者您能想到的任何其他方式。
您将如何帮助用户 节省数据
?留下评论,让您的想法被听到!
“如果您在桌面设备上使用 Chrome 的数据节省扩展程序,或选择在 Android 版 Chrome 上启用数据节省功能,Chrome 发送到服务器的每个请求都将包含一个值为 On 的 Save-Data 标头。”
我不确定我是否理解。这篇文章是关于如何使您的网站支持 Chrome 扩展程序的吗?这个扩展程序真的只有在网站专门支持它时才能工作吗?
嗨!感谢您抽出时间阅读我的文章。
我应该首先说明的是,
Save-Data
是 HTTP 客户端提示规范中定义的客户端提示。因此,浏览器供应商需要自行实施。目前,一些浏览器支持它。一些浏览器提供原生支持,但一些浏览器通过扩展程序支持Save-Data
。回答您的最后一个问题:是的,启用数据节省本身不会做任何事情,除了通过
Save-Data
请求头来表明它已启用。网站必须检测并对该字段进行操作。希望这有帮助。再次感谢您的阅读!
这篇文章根本没有清楚说明“save-data”标头的用途。应该在开头解释这一点。
我一开始以为,直到我读到文章的几个部分后,才意识到 save-data 指的是 a) 用户将页面内容保存到文件(html、网络存档等),或者 b) 将数据资源保存到缓存,甚至使用 WebStorage 来帮助管理页面所需的资源。
在不理解其用途的情况下,我回到了您链接到的 httpwg 规范页面,并且能够理解“save-data”标头是为了最小化页面和其他所需资源的大小。该标头更好的名称应该是 conserve-data(我知道这不是你的错,我们都必须接受规范所说的)。
嗨,Matt。感谢您抽出时间阅读,最重要的是,表达您的担忧。
很抱歉听到文章的意图在一开始并不十分清楚。作为一名厌恶缺乏清晰度的写作的人,这条评论以一种非常个人化(但建设性!)的方式触动了我。因此,我重新改写了开头段落,使其更清晰。我希望这能帮助未来的读者理解文章的要点,而不必像您一样读到一半才明白。
除此之外,我希望您发现这篇文章很有帮助,尽管它最初缺乏清晰度。
干杯!
-j
很棒的文章——干杯。对 Cory 的有用链接,他也在他们的 Twig 模板中使用它。
我想说,至少在英国,节省数据不再那么重要了,几乎每个人都有 4G 和 2GB – 100GB 的数据套餐 :)
我很想知道您对此有何看法?
谢谢。
在英国,您可能是对的,但最好不要假设。即使在美国这样的发达国家,在偏远地区的互联网用户也数量众多,网络连接速度非常慢。发展中国家的移动用户群体也很庞大,他们依赖预付费/后付费计量数据套餐。您不知道您的下一个用户是谁,因此伸出援手总不是坏事 :)
还应考虑删除网络字体。它们很容易累积到 100+ KB(例如,此页面)。如果用户正在节省数据,他们可能对系统字体感到满意。
是的!我不敢相信我没有想到这一点。如果像 Google 字体一样简单,则尤其容易做到。
您介意我根据您的反馈修改这篇文章吗?我将很乐意给予署名并链接到您的网站/Twitter/等等。
不用客气 :)
谢谢:我现在在我的完全静态网站http://m.earth.org.uk和http://www.earth.org.uk上使用了一部分 JPEG 图像实现了 Save-Data 功能。
请参见:http://www.earth.org.uk/note-on-site-technicals-5.html#jpgL
顺便说一句,我觉得使用“append”而不是“set”来设置 Vary 标头更安全,以防以后添加其他调整。
此致
Damon