菜单

HTTP Client Hints 介绍402.com:

2019年3月9日 - 计算机教程

HTTP Client Hints 介绍

2015/09/14 · HTML5 ·
算法

原文出处:
imququ(@屈光宇)   

最近几年各种 Web
技术一直在爆炸式发展,每天都有大量新东西涌现出来。针对这个现象,业内两位大佬最近先后发文表达了自己的观点:Stop
pushing the web
forward
Is
the web platform getting too
big?
。其实很早之前我就意识到以我目前的精力,吃透所有
Web 新技术几乎是不可能完成的任务,我关注新技术的侧重点放在了性能优化上。

今天我要向大家介绍的技术是:HTTP Client
Hints,也与性能优化有关。利用这项技术,HTTP
客户端(通常可以认为是浏览器)能够主动将一些特性告诉服务端,以便服务端更有针对性地输出内容。这项技术由我们熟知的
Ilya Grigorik
提出,目前还处在较为早期的阶段,较为正式的描述文档可以在这里找到。目前 Chrome
46
(beta)
 已支持它,IE
和 Firefox 则还在考虑中。

其实之前浏览器已经将很多自身特性放在 HTTP 请求中,例如下面这些头部字段:

通过以上这些头部字段,我们已经可以针对不同客户端输出不同内容。例如本博客对支持
Webp 格式的浏览器会使用 Webp 来减少图片大小;本博客还会通过 User-Agent
针对 IE 老版本禁用 localStorage 缓存策略。

但是有一些浏览器特性,我们无法直接获取,如屏幕分辨率、设备像素比(devicePixelRatio)、用户带宽等。而在移动
Web
中,为了尽可能节省用户流量,需要输出尺寸最合适的图片资源。为了解决这个问题,常见的方案有:1)使用
JS 获取这些特性,动态拼接图片 URL;2)使用 HTML 中的 sizes 和 srcset
属性、picture 标签或 CSS 中的 image-set 属性来实现响应式图片。方案 1
很简单,这里略过;方案 2
网上有很多相关文章,不熟悉的同学可以自行搜索「响应式图片」了解下。

这里看一个使用方案 2 中提到的 picture、sizes 和 srcset
实现的响应式图片代码(via):

<picture> <!– serve WebP to Chrome and Opera –> <source
media=”(min-width: 50em)” sizes=”50vw” srcset=”/image/thing-200.webp
200w, /image/thing-400.webp 400w, /image/thing-800.webp 800w,
/image/thing-1200.webp 1200w, /image/thing-1600.webp 1600w,
/image/thing-2000.webp 2000w” type=”image/webp”> <source
sizes=”(min-width: 30em) 100vw” srcset=”/image/thing-crop-200.webp 200w,
/image/thing-crop-400.webp 400w, /image/thing-crop-800.webp 800w,
/image/thing-crop-1200.webp 1200w, /image/thing-crop-1600.webp 1600w,
/image/thing-crop-2000.webp 2000w” type=”image/webp”> <!– serve
JPEGXR to Edge –> <source media=”(min-width: 50em)” sizes=”50vw”
srcset=”/image/thing-200.jpgxr 200w, /image/thing-400.jpgxr 400w,
/image/thing-800.jpgxr 800w, /image/thing-1200.jpgxr 1200w,
/image/thing-1600.jpgxr 1600w, /image/thing-2000.jpgxr 2000w”
type=”image/vnd.ms-photo”> <source sizes=”(min-width: 30em) 100vw”
srcset=”/image/thing-crop-200.jpgxr 200w, /image/thing-crop-400.jpgxr
400w, /image/thing-crop-800.jpgxr 800w, /image/thing-crop-1200.jpgxr
1200w, /image/thing-crop-1600.jpgxr 1600w, /image/thing-crop-2000.jpgxr
2000w” type=”image/vnd.ms-photo”> <!– serve JPEG to others –>
<source media=”(min-width: 50em)” sizes=”50vw”
srcset=”/image/thing-200.jpg 200w, /image/thing-400.jpg 400w,
/image/thing-800.jpg 800w, /image/thing-1200.jpg 1200w,
/image/thing-1600.jpg 1600w, /image/thing-2000.jpg 2000w”> <source
sizes=”(min-width: 30em) 100vw” srcset=”/image/thing-crop-200.jpg 200w,
/image/thing-crop-400.jpg 400w, /image/thing-crop-800.jpg 800w,
/image/thing-crop-1200.jpg 1200w, /image/thing-crop-1600.jpg 1600w,
/image/thing-crop-2000.jpg 2000w”> <!– fallback for browsers that
don’t support picture –> <img src=”/image/thing.jpg”
width=”50%”> </picture>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
<picture>
  <!– serve WebP to Chrome and Opera –>
  <source
    media="(min-width: 50em)"
    sizes="50vw"
    srcset="/image/thing-200.webp 200w, /image/thing-400.webp 400w,
        /image/thing-800.webp 800w, /image/thing-1200.webp 1200w,
        /image/thing-1600.webp 1600w, /image/thing-2000.webp 2000w"
    type="image/webp">
  <source
    sizes="(min-width: 30em) 100vw"
    srcset="/image/thing-crop-200.webp 200w, /image/thing-crop-400.webp 400w,
        /image/thing-crop-800.webp 800w, /image/thing-crop-1200.webp 1200w,
        /image/thing-crop-1600.webp 1600w, /image/thing-crop-2000.webp 2000w"
    type="image/webp">
  <!– serve JPEGXR to Edge –>
  <source
    media="(min-width: 50em)"
    sizes="50vw"
    srcset="/image/thing-200.jpgxr 200w, /image/thing-400.jpgxr 400w,
        /image/thing-800.jpgxr 800w, /image/thing-1200.jpgxr 1200w,
        /image/thing-1600.jpgxr 1600w, /image/thing-2000.jpgxr 2000w"
    type="image/vnd.ms-photo">
  <source
    sizes="(min-width: 30em) 100vw"
    srcset="/image/thing-crop-200.jpgxr 200w, /image/thing-crop-400.jpgxr 400w,
        /image/thing-crop-800.jpgxr 800w, /image/thing-crop-1200.jpgxr 1200w,
        /image/thing-crop-1600.jpgxr 1600w, /image/thing-crop-2000.jpgxr 2000w"
    type="image/vnd.ms-photo">
  <!– serve JPEG to others –>
  <source
    media="(min-width: 50em)"
    sizes="50vw"
    srcset="/image/thing-200.jpg 200w, /image/thing-400.jpg 400w,
        /image/thing-800.jpg 800w, /image/thing-1200.jpg 1200w,
        /image/thing-1600.jpg 1600w, /image/thing-2000.jpg 2000w">
  <source
    sizes="(min-width: 30em) 100vw"
    srcset="/image/thing-crop-200.jpg 200w, /image/thing-crop-400.jpg 400w,
        /image/thing-crop-800.jpg 800w, /image/thing-crop-1200.jpg 1200w,
        /image/thing-crop-1600.jpg 1600w, /image/thing-crop-2000.jpg 2000w">
  <!– fallback for browsers that don’t support picture –>
  <img src="/image/thing.jpg" width="50%">
</picture>

这段冗长的代码只是为了实现一张响应式图片,尽管有一些夸张,实际使用时一般不会写这么全,但从中可以得到一个结论:在客户端实现的策略越多,HTML
体积就越大越冗余,可维护性和可读性就越差。

而使用了 HTTP Client Hints
之后,浏览器在页面发起子资源请求时,会通过新增的一系列头部字段带上分辨率、设备像素比、图片宽度等信息,使得各种复杂的策略可以挪到服务端去实现了。下面来看一看具体细节:

首先,有了支持 HTTP Client Hints
的浏览器之后,页面上还需要显式启用它。这是因为不是所有服务端都实现了响应式输出策略,每次都发送这些新增的头部可能会造成浪费。

与往常一样,这个功能也可以通过 HTTP 响应头和 meta
标签两种方式开启并配置:

Accept-CH: DPR, Width, Viewport-Width

1
Accept-CH: DPR, Width, Viewport-Width

或:

<meta http-equiv=”Accept-CH” content=”DPR, Width, Viewport-Width”>

1
<meta http-equiv="Accept-CH" content="DPR, Width, Viewport-Width">

在启用了 HTTP Client Hints
的页面中,所有子资源请求(无论什么类型,无论什么方式创建),都会携带
Accept-CH 属性中所指明的头部,例如:

Accept: image/webp,image/*,*/*;q=0.8 Accept-Encoding: gzip, deflate,
sdch Accept-Language:
zh-CN,zh;q=0.8,en;q=0.6,en-US;q=0.4,ja;q=0.2,de;q=0.2,zh-TW;q=0.2,cs;q=0.2,pt;q=0.2,ko;q=0.2
Connection: keep-alive DPR: 2 Host: qgy18.imququ.com User-Agent:
Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_0) AppleWebKit/537.36
(KHTML, like Gecko) Chrome/46.0.2490.13 Safari/537.36 Viewport-Width:
1280 Width: 128

1
2
3
4
5
6
7
8
9
Accept: image/webp,image/*,*/*;q=0.8
Accept-Encoding: gzip, deflate, sdch
Accept-Language: zh-CN,zh;q=0.8,en;q=0.6,en-US;q=0.4,ja;q=0.2,de;q=0.2,zh-TW;q=0.2,cs;q=0.2,pt;q=0.2,ko;q=0.2
Connection: keep-alive
DPR: 2
Host: qgy18.imququ.com
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2490.13 Safari/537.36
Viewport-Width: 1280
Width: 128

有了这些头部,图片服务器可以知道客户端的 devicePixelRatio 是
2、图片宽度是 128px、支持 Webp 格式,所以输出 256px 的双倍 Webp
图最合适。但是浏览器怎么知道这个图片需要作为双倍图来使用呢(也就是说还是显示为
128px)?这就需要在响应头中增加下面这个字段作为 DPR 的回应:

Content-DPR: 2

1
Content-DPR: 2

需要注意的是,请求头中的 Width 字段,是根据 img 标签上的 sizes
属性算出来的。如果图片没有指定 sizes,或者图片请求是通过 JS
创建的,浏览器无法得知 Width,也就不会携带这个头部。

实际上,除了 DPR、Viewport-Width 和 Width
之外,文档还规定了两个字段,但是经过我的测试 Chrome 46
并没有支持它们,这里简单介绍下:

可以看出这两个属性,也是为了尽可能给用户节省带宽而设计的。可以预见,后续还会有更多字段加到
HTTP Client Hints 协议中来。随着 HTTP/2
的普及,头部压缩使得增加几个头部字段带来的开销变得很小了。

值得注意的是,使用了 HTTP Client Hints 之后,服务端针对同一个 URL
可能会输出不同的内容,所以无论是中间节点,还是浏览器,在实现响应 Cache
时必须小心,需要针对不同的情况缓存多份内容。这需要用到 HTTP/1 中的 
Vary 响应头,例如:

Vary: DPR, Width, Downlink

1
Vary: DPR, Width, Downlink

表明如果需要缓存这个响应,在生成缓存 Key 的时候需要将请求头中的
DPR、Width 和 Downlink 的值计算进去。

好了,HTTP Client Hints 技术就介绍到这里。很欣慰地看到,大部分 Web
新技术都是在给 HTML、CSS 和 JavaScript
增加功能和特性,而这项技术却是把之前复杂的代码和逻辑往后移,让我们的
HTML
代码能够轻装上阵。一些开源图片处理系统已经开始支持这个新特性了,国外的一些
CDN 托管服务肯定也在蠢蠢欲动,我十分期待它的未来。

1 赞 收藏
评论

402.com 1

最近几年各种 Web
技术一直在爆炸式发展,每天都有大量新东西涌现出来。针对这个现象,业内两位大佬最近先后发文表达了自己的观点:Stop
pushing the web
forward
Is
the web platform getting too
big?
。其实很早之前我就意识到以我目前的精力,吃透所有
Web 新技术几乎是不可能完成的任务,我关注新技术的侧重点放在了性能优化上。

今天我要向大家介绍的技术是:HTTP Client
Hints,也与性能优化有关。利用这项技术,HTTP
客户端(通常可以认为是浏览器)能够主动将一些特性告诉服务端,以便服务端更有针对性地输出内容。这项技术由我们熟知的
Ilya Grigorik
提出,目前还处在较为早期的阶段,较为正式的描述文档可以在这里找到。目前
Chrome 46
(beta)

已支持它,IE 和 Firefox 则还在考虑中。

其实之前浏览器已经将很多自身特性放在 HTTP 请求中,例如下面这些头部字段:

通过以上这些头部字段,我们已经可以针对不同客户端输出不同内容。例如本博客对支持
Webp 格式的浏览器会使用 Webp 来减少图片大小;本博客还会通过 User-Agent
针对 IE 老版本禁用 localStorage 缓存策略。

但是有一些浏览器特性,我们无法直接获取,如屏幕分辨率、设备像素比(devicePixelRatio)、用户带宽等。而在移动
Web
中,为了尽可能节省用户流量,需要输出尺寸最合适的图片资源。为了解决这个问题,常见的方案有:1)使用
JS 获取这些特性,动态拼接图片 URL;2)使用 HTML 中的 sizes 和 srcset
属性、picture 标签或 CSS 中的 image-set 属性来实现响应式图片。方案 1
很简单,这里略过;方案 2
网上有很多相关文章,不熟悉的同学可以自行搜索「响应式图片」了解下。

这里看一个使用方案 2 中提到的 picture、sizes 和 srcset
实现的响应式图片代码(via):

HTML<picture>
  <!-- serve WebP to Chrome and Opera -->
  <source
    media="(min-width: 50em)"
    sizes="50vw"
    srcset="/image/thing-200.webp 200w, /image/thing-400.webp 400w,
        /image/thing-800.webp 800w, /image/thing-1200.webp 1200w,
        /image/thing-1600.webp 1600w, /image/thing-2000.webp 2000w"
    type="image/webp">
  <source
    sizes="(min-width: 30em) 100vw"
    srcset="/image/thing-crop-200.webp 200w, /image/thing-crop-400.webp 400w,
        /image/thing-crop-800.webp 800w, /image/thing-crop-1200.webp 1200w,
        /image/thing-crop-1600.webp 1600w, /image/thing-crop-2000.webp 2000w"
    type="image/webp">
  <!-- serve JPEGXR to Edge -->
  <source
    media="(min-width: 50em)"
    sizes="50vw"
    srcset="/image/thing-200.jpgxr 200w, /image/thing-400.jpgxr 400w,
        /image/thing-800.jpgxr 800w, /image/thing-1200.jpgxr 1200w,
        /image/thing-1600.jpgxr 1600w, /image/thing-2000.jpgxr 2000w"
    type="image/vnd.ms-photo">
  <source
    sizes="(min-width: 30em) 100vw"
    srcset="/image/thing-crop-200.jpgxr 200w, /image/thing-crop-400.jpgxr 400w,
        /image/thing-crop-800.jpgxr 800w, /image/thing-crop-1200.jpgxr 1200w,
        /image/thing-crop-1600.jpgxr 1600w, /image/thing-crop-2000.jpgxr 2000w"
    type="image/vnd.ms-photo">
  <!-- serve JPEG to others -->
  <source
    media="(min-width: 50em)"
    sizes="50vw"
    srcset="/image/thing-200.jpg 200w, /image/thing-400.jpg 400w,
        /image/thing-800.jpg 800w, /image/thing-1200.jpg 1200w,
        /image/thing-1600.jpg 1600w, /image/thing-2000.jpg 2000w">
  <source
    sizes="(min-width: 30em) 100vw"
    srcset="/image/thing-crop-200.jpg 200w, /image/thing-crop-400.jpg 400w,
        /image/thing-crop-800.jpg 800w, /image/thing-crop-1200.jpg 1200w,
        /image/thing-crop-1600.jpg 1600w, /image/thing-crop-2000.jpg 2000w">
  <!-- fallback for browsers that don't support picture -->
  <img src="/image/thing.jpg" width="50%">
</picture>

这段冗长的代码只是为了实现一张响应式图片,尽管有一些夸张,实际使用时一般不会写这么全,但从中可以得到一个结论:在客户端实现的策略越多,HTML
体积就越大越冗余,可维护性和可读性就越差。

而使用了 HTTP Client Hints
之后,浏览器在页面发起子资源请求时,会通过新增的一系列头部字段带上分辨率、设备像素比、图片宽度等信息,使得各种复杂的策略可以挪到服务端去实现了。下面来看一看具体细节:

首先,有了支持 HTTP Client Hints
的浏览器之后,页面上还需要显式启用它。这是因为不是所有服务端都实现了响应式输出策略,每次都发送这些新增的头部可能会造成浪费。

与往常一样,这个功能也可以通过 HTTP 响应头和 meta
标签两种方式开启并配置:

Accept-CH: DPR, Width, Viewport-Width

或:

<meta http-equiv="Accept-CH" content="DPR, Width, Viewport-Width">

相关文章

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图