「译」开发者的责任之 HTTP header


本文是访谈“开发者的责任之Http Header”的书面版本。 您能够查看 幻灯片录音


译者注

本文篇幅较长,所有阅读完大约须要10分钟。如下是本文概览。css

  • HTTPS和HSTS(如何创建安全的链接)
  • CSP(内容安全策略)
  • 缓存控制
  • immutable - 从不请求资源两次
  • Accept-Encoding (压缩算法说明)
  • Accept - 提供正确的图像格式
  • Accept-CH - 提供适当大小的图像
  • rel = preload (预加载,减小等待时间)
  • Feature-Policy (功能策略)

「译」开发者的责任之Http Header


本文是访谈“开发者的责任之Http Header”的书面版本。 您能够查看 幻灯片录音


前言

原文连接:HTTP headers for the responsible developer
现在,使用网络是许多人的默认状态。 咱们都花时间购物,聊天,阅读文章,寻找方向等信息。 网络将咱们与整个世界联系起来,但大多数状况下,网络将人们链接起来。 我本身已经使用网络已有20年了,八年前,当我成为网络开发人员时,我与它的关系发生了变化。html

开发人员链接了人们。
开发人员帮助了人们。
开发人员支持着人们。
**
开发人员有能力为每一个人构建Web服务,但须要负责任地使用该功能。 最重要的是,创建有助于和帮助人们的事物。
在本文中,我想分享HTTP Header 如何帮助您构建更好的产品,以便为每一个人提供更好的Web服务。前端

HTTP  - 超文本传输协议

咱们先谈谈HTTP。 HTTP是计算机用于经过Web请求和发送数据的协议。
当浏览器从服务器请求资源时,它使用HTTP。 此请求包括一组键值对,提供浏览器版本或其理解的文件格式等信息。 这些键值对称为 request headers
服务器使用所请求的资源进行应答,但也会发送 response headers,提供有关资源或服务器自己的信息。git

Request:
GET https://the-responsible.dev/
Accept: text/html,application/xhtml+xml,application/xml
Accept-Encoding: gzip, deflate, br
Accept-Language: en-GB,en-US;q=0.9,en;q=0.8,de;q=0.7
...

Response:
Connection: keep-alive
Content-Type: text/html; charset=utf-8
Date: Mon, 11 Mar 2019 12:59:38 GMT
...
Response Body
复制代码

HTTP是当今网络的基础,它提供了许多改善用户体验的方法。 让咱们深刻探讨如何使用HTTP Header构建安全,经济且值得尊重的Web服务。github

网络必须安全

我历来没有在浏览互联网时感到不安全。 我对网络的了解越多,我就越关注。 您能够阅读有关黑客可能会改变全球CDN托管的 库随机网站在其访问者的浏览器中挖掘加密货币以及人们将社交工程按期用于成功的开源项目。 这很差,但为何要关心呢?web

若是您今天正在为网络构建,那么您不只要编写代码。 现在,Web开发包括许多在同一站点上工做的人。 您可能也提供了大量的开源代码。 此外,您能够包含多个第三方脚本用于销售目的。 数百人提供您网站上运行的代码。 开发人员必须应对这一现实。算法

你应该相信全部这些人及其全部源代码吗?
我认为你不能相信任何第三方代码。 幸运的是,有一些方法能够保护您的网站并使其更安全。 此外,像头盔这样的工具能够帮助确保你的快递申请的安全
若是您想分析您的网站上运行了多少第三方代码,您能够查看您选择的开发人员工具的网络面板,或者尝试使用Request Map Generatorchrome

HTTPS和HSTS  - 确保您的链接安全

安全链接是安全互联网的基础。 若是没有经过HTTPS运行的加密请求,您没法肯定您的网站与访问者之间是否存在任何人。 一我的能够快速启动一个公共wifi网络,并对一个链接任何人进行中间攻击。 你多久使用一次公共wifi? 并且,你常常检查它是否值得信赖?express

幸运的是,今天TLS证书是免费的; HTTPS已成为一种标准,浏览器供应商仅在安全链接上提供最早进的功能,甚至将非HTTPS网站标记为不安全,从而推进HTTPS的采用。 不幸的是,咱们一直没有安全浏览。 当有人想打开一个网站时,他们没有将协议输入地址栏(他们为何要这样作?)。 此操做会致使未加密的HTTP请求。 安全运行站点而后重定向到HTTPS。 可是若是有人拦截了第一个无担保的请求怎么办?
您可使用HSTS response headers(HTTP严格传输安全性)告诉浏览器您的网站仅经过HTTPS工做。npm

Strict-Transport-Security: max-age=1000; includeSubDomains; preload
复制代码

Header 告诉浏览器您不想使用HTTP请求,它会自动使用安全链接向相同的源发出如下请求。 当您尝试再次经过HTTP访问相同的URL时,浏览器将在内部使用HTTPS和重定向。

您能够配置此设置应该激活的时间长度(以秒为单位的 max-age),以便您可能但愿再次使用HTTP。 若是要包含子域,则可使用 includeSubDomains 配置子域。

若是您想加倍努力并但愿确保浏览器永远不会经过HTTP请求您的站点,您还能够设置preload指令并将您的站点提交到全局列表。 若是您的站点的HSTS配置知足最小年龄为一年的要求而且对于子域是活动的,则它能够包含在仅经过HTTPS工做的站点的内部浏览器记录中。

你有没有想过为何你不能再经过HTTP使用my-site.dev这样的本地环境了? 此内部记录的缘由是 -  .dev域名自动包含在此列表中,由于它在2019年2月成为真正的顶级域名。

HSTS Header 不只使您的网站更安全,并且还加快了它的速度。 想象一下有人经过慢速移动链接访问您的网站。 若是第一个请求是经过HTTP进行的,只是为了接收重定向,那么用户能够花费几秒钟而不会看到任何内容。 使用HSTS,您能够节省这些时间,浏览器会自动使用HTTPS。

CSP  - 明确您网站上容许的内容

既然您的站点经过安全链接运行,您可能会遇到这样的问题:因为混合内容策略,浏览器开始阻止发送到不安全地址的请求。 内容安全策略(CSP)标头提供了处理这些状况的绝佳方法。 您能够经过提供的HTML中的元素或HTTP Header 定义CSP规则集。
Content-Security-Policy: upgrade-insecure-requests
upgrade-insecure-requests 指令告诉浏览器神奇地将全部HTTP请求升级到HTTPS。
CSP不只仅是关于使用的协议。 它提供了详细的方法来定义站点上容许的资源和操做。 您能够定义例如应该执行哪些脚本或应该从哪里加载图像。 若是不容许某些内容,浏览器会阻止它并阻止您的网站受到潜在的攻击。


在撰写本文时,CSP有24种不一样的配置选项。 这些选项包括脚本而不是样式表,甚至是服务工做者的起源。

您能够在 MDN上找到完整的概述。

使用CSP,您能够肯定您的网站应包含哪些内容以及不包含哪些内容。

Content-Security-Policy: default-src 'self'; script-src 'self' just-comments.com www.google-analytics.com production-assets.codepen.io storage.googleapis.com; style-src 'self' 'unsafe-inline'; img-src 'self' data: images.contentful.com images.ctfassets.net www.gravatar.com www.google-analytics.com just-comments.com; font-src 'self' data:; connect-src 'self' cdn.contentful.com images.contentful.com videos.contentful.com images.ctfassets.net videos.ctfassets.net service.just-comments.com www.google-analytics.com; media-src 'self' videos.contentful.com videos.ctfassets.net; object-src 'self'; frame-src codepen.io; frame-ancestors 'self'; worker-src 'self'; block-all-mixed-content; manifest-src 'self' 'self'; disown-opener; prefetch-src 'self'
复制代码

上面的规则集是我为个人我的网站发布的规则集,若是您认为这个CSP示例定义很是难以提出 - 您彻底正确。 在个人我的网站上实施CSP规则集让我尝试了三次尝试。 我部署它并回滚,由于它屡次打破了个人网站。 有一种更好的方法能够作到这一点。

为避免破坏您的网站,CSP还提供仅限报告的选项。

Content-Security-Policy-Report-Only: default-src 'self'; ... report-uri https://stefanjudis.report-uri.com/r/d/csp/reportOnly
复制代码

使用Content-Security-Policy-Report-Only模式浏览器仅将阻止的资源记录到控制台而不是阻止它们。 此报告机制为您提供了检查和调整规则集的方法。

两个标题,Content-Security-PolicyContent-Security-Policy-Report-Only,还提供了一种定义端点以将违规和日志信息发送到(report-uri)的方法。 您能够设置日志记录服务器并使用发送的日志信息来调整CSP规则,直到它准备好上线。

建议的过程是:首先仅在报告模式下部署CSP,使用实际流量分析传入的违规行为,而且只有在再也不出现违反受控资源的状况下才会启用它。

若是您正在寻找能够帮助您处理这些日志的服务,我正在使用Report URI,它会很好的帮助你。

总体采用CSP

目前,浏览器对CSP的支持很好,但不幸的是,没有多少网站在使用它。 要查看有多少网站使用CSP提供内容,我在HTTP Archive上运行了一个查询,发现只有6%的已爬网站点使用CSP。 我认为咱们能够作得更好,使网络更安全,避免咱们的用户在不知情的状况下挖掘加密货币

jAQW_VflYXdzcl9ER0yTVPGpTBRQAOVZrIvgjSW6ucayZ.width-1600.jpg

Web 必须是可负担的

在我写这篇文章的时候,我在家里使用个人快速Wi-Fi链接坐在一台相对较新的MacBook前面。 开发人员常常忘记这样的设置不是咱们大多数用户的默认设置。 访问咱们网站的人使用的是旧手机,而且处于糟糕的链接状态。 拥有数百个请求的繁重和臃肿的网站给他们带来了糟糕的体验。

这不只仅是关于体验的。 人们根据他们居住的地点为数据支付不一样的金额。 想象一下,你正在创建一个医院网站。 有关此特定网站的信息可能对人们相当重要而且能够挽救生命。

若是医院网站上的页面是5MB,那么它不只速度慢,并且对于最须要它的人来讲也可能太昂贵。 与非洲5MB数据的价格相比,欧洲或美国的5MB价格可有可无。 开发人员有责任让每一个人都能负担得起网络。 这个职责包括提供正确的资源,评估正确使用的工具(你真的须要一个登录页面的JS框架吗?),以及避免请求。

缓存控制 - 避免对未更改资源的请求

今天的网站很容易包含数百种资源,从样式表到脚本文件再到图像。 使用Cache-Control标头,开发人员能够定义资源应被视为“新鲜”多长时间,而且能够从浏览器缓存中提供。

Cache-Control: max-age=30, public
复制代码

经过设置适当的Cache-Control,能够保存数据传输,而且能够从浏览器缓存中使用文件必定的秒数(max-age)。 浏览器应在时间跨度结束后从新验证缓存的资源。

可是,当访问者刷新页面时,浏览器仍会从新验证包含引用资源的页面,以确保缓存的数据仍然有效。 服务器以304标头响应,表示缓存的数据仍然良好,或200服务于更新的数据。 这能够节省传输的数据,但不必定是请求。

这是 immutable 特征发挥做用的地方。

immutable - 从不请求资源两次

在现代前端应用程序中,样式表和脚本文件一般具备惟一的文件名,如styles.123abc.css。 此文件名取决于特定文件的内容。 当这些文件的内容发生更改时,会生成不一样的文件名。

这些惟一文件可能会被永久缓存,包括用户刷新页面时的状况。 不可变特征能够告诉浏览器不要在特定时间范围内从新验证资源。 这对指纹验证的资源颇有意义,有助于避免从新验证请求。

Cache-Control: max-age=31536000, public, immutable
复制代码

最佳缓存很是困难,特别是浏览器缓存不是很直观,由于它提供了多种配置。 我建议您查看如下资源:

Accept-Encoding  - 压缩到最大值(uhm ...最小值)

使用 Cache-control,咱们能够保存请求并减小重复经过线路传输的数据量。 咱们不只能够保存请求,还能够缩小转移的内容。
在提供资源时,开发人员应确保尽量少地发送数据。 对于像HTML这样的基于文本的资源,CSS和JavaScript压缩在保存传输数据方面起着重要做用。
目前最经常使用的压缩是GZIP。 服务器足够快,能够动态压缩文本文件,并在请求时提供压缩数据。 GZIP再也不是最好的选择了。
若是您检查浏览器对基于文本的文件(如HTML,CSS和JavaScript)所作的请求,并查看请求标头,您将找到accept-encoding Header。

Accept-Encoding: gzip, deflate, br
复制代码

此标头告诉服务器它理解的压缩算法。 不太知名的br表明是 Brotli(一种压缩算法),是谷歌和Facebook等高流量网站使用的压缩。 要使用Brotli,您的网站必须在HTTPS上运行。

此压缩算法在建立时考虑了小文件大小。 当您在本地计算机上试一试并手动压缩文件时,您会发现Brotli确实比GZIP压缩得更好。

您可能据说Brotli压缩也会变慢。 缘由是Brotli有11种压缩模式,而且选择默认模式以保证较小的文件大小,从而致使编码时间较长。 另外一方面,GZIP有9种模式,而且考虑到速度和文件大小,选择默认模式。
此决定使得Brotli的默认模式不适合进行即时压缩,但若是更改压缩模式,您能够实现更小的文件大小,速度与GZIP至关。 您甚至可使用它进行即时压缩,并将其视为支持浏览器的潜在GZIP替代品。

除此以外,若是您想得到最大的文件节省,您可能会忘记在构建过程当中使用zopfli和Brotli文件动态压缩文件和预生成优化的GZIP文件以静态地为它们提供服务的想法。

若是您想了解更多关于Brotli压缩以及它与GZIP的比较,Akamai的人们围绕这一主题进行了普遍的研究。

Accept and Accept-CH-为用户提供量身定制的资源

优化文本资产很是适合保存千字节,可是像图像这样的较重资源能够节省更多数据。

Accept - 提供正确的图像格式

浏览器不只告诉咱们他们理解的压缩算法。 当您的浏览器请求图像时,它还会提供有关其理解的文件格式的信息。

Accept: image/webp, image/apng, image/*,*/*;q=0.8
复制代码

围绕新图像格式的竞争已经持续了几年,但如今看起来像webp赢了。 Webp是Google发明的一种图像格式,目前对webp图像的支持很是好。

使用此请求标头,即便浏览器请求image.jpg致使文件较小,开发人员也能够提供 **webp **图像。 Dean Hume写了一篇关于如何在服务工做者中作这件事的好指南。 那太酷了!

9JczExPcmc402uz1B2mY_KmhuaQNl6UExmSYcs2ZH7yND.width-1600.jpg

Accept-CH  - 提供适当大小的图像

您还能够启用客户端提示以支持浏览器。 客户端提示是一种告诉浏览器发送附加标题的方法,这些标题提供有关视口宽度,图像宽度甚至网络条件的信息,如RTT(往返时间)和链接类型(如2g)。

您能够经过包含元元素来启用它们:

<meta http-equiv="Accept-CH" content="Viewport-Width, Downlink">
<meta http-equiv="Accept-CH-Lifetime" content="86400">
复制代码

或者在初始HTML请求上设置标题:

Accept-CH: Width, Viewport-Width
Accept-CH-Lifetime: 100
复制代码

支持浏览器将开始在如下请求中发送定义的时间跨度(Accept-CH-Lifetime,以秒为单位)的附加信息,这些请求能够帮助开发人员根据用户条件定制示例图像,而无需更改任何HTML。
要在服务器端接收例如图像宽度等附加信息,您能够为图像配备尺寸属性,以便为浏览器提供有关如何布置图像的其余信息。

<!-- this images is laid over the full width | 100 viewport width -->
<img class="w-100" src="/img/header.jpg" alt="" sizes="100vw">
复制代码

使用最初收到的Accept-CH响应标题和配备了支持浏览器的sizes属性的图像将在图像请求中包含视口宽度和宽度标题,告诉您哪一个图像最适合。

8u07oEaYg3fBaV6Z35RcBDXW7hehK8wPrPSthhRpQlHN3.width-1600.jpg

拥有支持的图像格式和图像尺寸,您能够发送定制的媒体,而无需编写容易出错的图像元素,重复处理文件格式和大小以下所示。

<picture>
  <!-- serve WebP to Chrome, Edge, Firefox 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 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>
复制代码

经过访问视口宽度和图像大小的可能性,您能够将资产调整大小逻辑移动到服务器的中心位置。
你必须考虑,只是由于你手头有准确的图像宽度,你不想为每一个宽度建立图像。 发送特定维度范围(image-200,image-300,...)的图像有助于利用CDN缓存并节省计算时间。

此外,利用服务工做者等当前技术,您甚至能够在客户端中拦截和更改请求以提供最佳图像文件。 经过启用的客户端提示,服务工做人员能够访问布局信息,并结合图像API(例如Cloudinary),您能够在浏览器中调整图像URL以接收正确大小的图像。

若是您正在寻找有关客户提示的更多信息,能够查看Jeremy Wagner的文章或Ilya Grigorik关于该主题的文章。

网络必须尊重他人

咱们全部人天天都要上网几个小时,我认为最后一个方面很是重要 - 网络必须尊重他人。

预加载 - 减小等待时间

做为开发人员,咱们但愿确保重视用户的时间。 没人想浪费时间。 如前面部分所述,提供正确的数据在节省时间和数据方面发挥着重要做用。 这不只是关于提出的请求,还关于这些请求的时间和顺序。

让咱们想一个例子:若是您在网站中包含样式表,浏览器在加载以前不会显示任何内容。 虽然没有显示任何内容,但浏览器仍会继续解析HTML以查找要获取的其余资源。 加载和解析样式表时,它可能包含对其余关键资源的引用,例如必须请求的字体。 此顺序过程能够增长访问者的加载时间。

使用rel = preload,您能够向浏览器提供有关在不久的未来请求的资源的信息。

您能够经过HTML元素预加载资源:

<link rel="preload" href="/font.woff2" as="font" type="font/woff2" crossorigin="anonymous">
复制代码

或者是Headers:

Link: </font.woff2>; rel=preload; as=font; no-push
复制代码

这样,浏览器接收标头或发现连接元素并当即请求资源,以便在须要时它们已经位于浏览器缓存中。 此过程重视访问者的时间。
要以最佳方式预加载资源并了解全部配置,我建议您查看如下资源:

Feature-Policy- 不要成为讨厌的人

若是最后有一件事我不想再看到,那就是网站平白无故地要求我得到权限。 我只能引用个人同事菲尔纳什的话题。

**不要求页面加载的通知权限。

**
开发人员应该尊重访问者,不要创建惹恼访问者的网站。 人们只需单击全部权限对话框便可。 网站和开发人员失去了不少信任,若是咱们开发人员没有仔细使用它们,那么全部新的闪亮网页功能都会失去力量。

可是,若是您的站点必须包含大量第三方代码而且全部这些脚本会触发一个又一个的权限对话,该怎么办? 如何确保全部包含的脚本都表现出来?

这是Feature-Policy Header发挥做用的地方。 使用此标头,您能够定义容许的功能,并限制可能由您网站中运行代码的其余人触发的弹出权限对话框。

Feature-Policy: vibrate 'none'; geolocation 'none'
复制代码

您可使用标头为您的网站定义它,但也能够为嵌入式内容定义它,例如iframe,这对于第三方集成是必需的。

<iframe allow="camera 'none'; microphone 'none'">
复制代码

在撰写本文时,功能策略具备很高的实验性,但若是你看看即将推出的选项,那就很是使人兴奋了。 在不久的未来,开发人员不只能够限制本身并防止恼人的对话框的传输,还可能阻止非优化的媒体。 这些功能将在用户体验方面产生重大影响。


您能够在  MDN 上找到完整的概述。

查看上面的功能策略列表,您可能想知道最烦人的一次推送通知发生了什么。 事实证实推送通知的功能策略的实现比预期更难。 若是您想了解更多信息,能够按照提交的GitHub issues 进行操做。

使用功能政策,您能够确保您和您的第三方不会将您的网站变成许可解雇竞赛,遗憾的是,这种竞争已经成为当今许多网站的默认状态。

网络必须适合全部人

在本文中,我只介绍了一些有助于改善用户体验的标题。 若是你想看到几乎完整的标题及其可能性的概述,我能够推荐看看Christian Schaefer的幻灯片“HTTP标题 - 隐藏的冠军”。

我知道今天创建一个伟大的网站是很是具备挑战性的。 开发人员必须考虑设计,设备,框架,以及是......标题也起做用。 但愿本文给出了一些想法,您将在下一个Web项目中考虑安全性,可负担性和尊重,由于这些因素使Web真正适合每一个人。

做者联系方式

相关文章
相关标签/搜索