超文本传输协议(HTTP)是一个用于传输超媒体文档(例如 HTML)的应用层协议。它是为 Web 浏览器与 Web 服务器之间的通信而设计的,
但也可以用于其他目的。HTTP 遵循经典的客户端—服务端模型,客户端打开一个连接以发出请求,然后等待直到收到服务器端响应。
HTTP 是无状态协议,这意味着服务器不会在两个请求之间保留任何数据(状态)。
HTTP概述
HTTP 是一种用作获取诸如 HTML 文档这类资源的协议。它是 Web 上进行任何数据交换的基础,同时,
也是一种客户端—服务器(client-server)协议,也就是说,请求是由接受方——通常是浏览器——发起的。
一个完整网页文档是由获取到的不同文档组件——像是文本、布局描述、图片、视频、脚本等——重新构建出来的。
客户端与服务端之间通过交换一个个独立的消息(而非数据流)进行通信。由客户端——通常是个浏览器——发出的消息被称作请求(request),
由服务端发出的应答消息被称作响应(response)。
20 世纪 90 年代,HTTP 作为一套可扩展的协议被设计出来,并随时间不断演进。HTTP 是一种应用层的协议,通过 TCP,
或者是 TLS——一种加密过的 TCP 连接——来发送,当然,理论上来说可以借助任何可靠的传输协议。受益于 HTTP 的可扩展性,
时至今日,它不仅可以用来获取超文本文档,还可用来获取图片、视频或者向服务端发送信息,比如填写好的 HTML 表单。
HTTP 还可以用来获取文档的部分内容,以便按需更新 Web 页面。
HTTP缓存
HTTP 缓存会存储与请求关联的响应,并将存储的响应复用于后续请求。可复用性有几个优点。首先,由于不需要将请求传递到源服务器,因此客户端和缓存越近,
响应速度就越快。最典型的例子是浏览器本身为浏览器请求存储缓存。此外,当响应可复用时,源服务器不需要处理请求——因为它不需要解析和路由请求、
根据 cookie 恢复会话、查询数据库以获取结果或渲染模板引擎。这减少了服务器上的负载。缓存的正确操作对系统的稳定运行至关重要。
私有缓存
私有缓存是绑定到特定客户端的缓存——通常是浏览器缓存。由于存储的响应不与其他客户端共享,因此私有缓存可以存储该用户的个性化响应。
另一方面,如果个性化内容存储在私有缓存以外的缓存中,那么其他用户可能能够检索到这些内容——这可能会导致无意的信息泄露。
如果响应包含个性化内容并且你只想将响应存储在私有缓存中,则必须指定 private 指令。
1 | Cache-Control: private |
个性化内容通常由 cookie 控制,但 cookie 的存在并不能表明它是私有的,因此单独的 cookie 不会使响应成为私有的。
请注意,如果响应具有 Authorization 标头,则不能将其存储在私有缓存(或共享缓存,除非 Cache-Control 指定的是 public)中。
共享缓存
共享缓存位于客户端和服务器之间,可以存储能在用户之间共享的响应。共享缓存可以进一步细分为代理缓存和托管缓存。
代理缓存
除了访问控制的功能外,一些代理还实现了缓存以减少网络流量。这通常不由服务开发人员管理,因此必须由恰当的 HTTP 标头等控制。然而,在过去,
过时的代理缓存实现——例如没有正确理解 HTTP 缓存标准的实现——经常给开发人员带来问题。
Kitchen-sink 标头如下所示,用于尝试解决不理解当前 HTTP 缓存规范指令(如 no-store)的“旧且未更新的代理缓存”的实现。
1 | Cache-Control: no-store, no-cache, max-age=0, must-revalidate, proxy-revalidate |
然而,近年来,随着 HTTPS 变得越来越普遍,客户端/服务器通信变得加密,在许多情况下,路径中的代理缓存只能传输响应而不能充当缓存。
因此,在这种情况下,无需担心甚至无法看到响应的过时代理缓存的实现。另一方面,如果TLS桥接代理通过在PC上安装来自组织管理的 CA (en-US) 证书,
以中间人方式解密所有通信,并执行访问控制等,则可以查看响应的内容并将其缓存。但是,
由于证书透明度(certificate transparency)在最近几年变得很普遍,
并且一些浏览器只允许使用证书签署时间戳(signed certificate timestamp)颁发的证书,因此这种方法需要应用于企业策略。
在这样的受控环境中,无需担心代理缓存“已过时且未更新”。
托管缓存
托管缓存由服务开发人员明确部署,以降低源服务器负载并有效地交付内容。示例包括反向代理、CDN 和 service worker 与缓存 API 的组合。
托管缓存的特性因部署的产品而异。在大多数情况下,你可以通过 Cache-Control 标头和你自己的配置文件或仪表板来控制缓存的行为。
例如,HTTP 缓存规范本质上没有定义显式删除缓存的方法——但是使用托管缓存,可以通过仪表板操作、API 调用、重新启动等实时删除已经存储的响应。
这允许更主动的缓存策略。也可以忽略标准 HTTP 缓存规范协议以支持显式操作。例如,可以指定以下内容以选择退出私有缓存或代理缓存,
同时使用你自己的策略仅在托管缓存中进行缓存。
1 | Cache-Control: no-store |
例如,Varnish Cache 使用 VCL(Varnish Configuration Language,一种 DSL (en-US))逻辑来处理缓存存储,
而 service worker 结合缓存 API 允许你在 JavaScript 中创建该逻辑。这意味着如果托管缓存故意忽略 no-store 指令,
则无需将其视为“不符合”标准。你应该做的是,避免使用 kitchen-sink 标头,但请仔细阅读你正在使用的任何托管缓存机制的文档,
并确保你选择的方式可以正确的控制缓存。请注意,某些 CDN 提供自己的标头,这些标头仅对该 CDN 有效(例如,Surrogate-Control)。
目前,正在努力定义一个 CDN-Cache-Control 标头来标准化这些标头。
HTTP Cookie
HTTP Cookie(也叫 Web Cookie 或浏览器 Cookie)是服务器发送到用户浏览器并保存在本地的一小块数据。浏览器会存储 cookie 并在下次向同一服务器再发起请求时携带并发送到服务器上。通常,它用于告知服务端两个请求是否来自同一浏览器——如保持用户的登录。Cookie 使基于无状态的 HTTP 协议记录稳定的状态信息成为了可能。
Cookie 主要用于以下三个方面:
- 会话状态管理:如用户登录状态、购物车、游戏分数或其他需要记录的信息
- 个性化设置:如用户自定义设置、主题和其他设置
- 浏览器行为跟踪:如跟踪分析用户行为等
Cookie 曾一度用于客户端数据的存储,因当时并没有其他合适的存储办法而作为唯一的存储手段,但现在推荐使用现代存储 API。由于服务器指定 Cookie 后,浏览器的每次请求都会携带 Cookie 数据,会带来额外的性能开销(尤其是在移动环境下)。新的浏览器 API 已经允许开发者直接将数据存储到本地,如使用 Web storage API(localStorage 和 sessionStorage)或 IndexedDB 。
创建 Cookie
定义 Cookie 的生命周期
限制访问 Cookie
定义 Cookie 发送的位置
安全
跟踪和隐私
跨域资源共享(CORS)
跨源资源共享(CORS,或通俗地译为跨域资源共享)是一种基于 HTTP 头的机制,该机制通过允许服务器标示除了它自己以外的其他源(域、协议或端口),使得浏览器允许这些源访问加载自己的资源。跨源资源共享还通过一种机制来检查服务器是否会允许要发送的真实请求,该机制通过浏览器发起一个到服务器托管的跨源资源的“预检”请求。在预检中,浏览器发送的头中标示有 HTTP 方法和真实请求中会用到的头。
跨源 HTTP 请求的一个例子:运行在 https://domain-a.com 的 JavaScript 代码使用 XMLHttpRequest 来发起一个到 https://domain-b.com/data.json 的请求。出于安全性,浏览器限制脚本内发起的跨源 HTTP 请求。例如,XMLHttpRequest 和 Fetch API 遵循同源策略。这意味着使用这些 API 的 Web 应用程序只能从加载应用程序的同一个域请求 HTTP 资源,除非响应报文包含了正确 CORS 响应头。
CORS 机制允许 Web 应用服务器进行跨源访问控制,从而使跨源数据传输得以安全进行。现代浏览器支持在 API 容器中(例如 XMLHttpRequest 或 Fetch)使用 CORS,以降低跨源 HTTP 请求所带来的风险。
HTTP 客户端提示(Client Hint)
客户端提示是一组响应标头,服务器可以使用它来主动从客户端请求关于设备、网络、用户以及用户代理指定的首选项的信息。
然后,服务器可以根据客户端选择提供的信息来确定发送哪些资源。
HTTP 的演变
简单描述了从早期版本的 HTTP 到现代 HTTP/2,新兴的 HTTP/3 以及未来版本的 HTTP 这个过程中发生的变更。
Mozilla Web 安全准则
一系列用于帮助运营团队创建安全的 Web 应用程序的技巧。
HTTP 消息
描述了 HTTP/1.x 和 HTTP/2 中不同种类消息的类型和结构。
典型的 HTTP 会话
展现并解释了一个常见 HTTP 会话的流程。
HTTP/1.x 中的连接管理
描述了在 HTTP/1.x 中的三种连接管理模型,以及它们的优点和缺点。
HTTP 标头
HTTP 消息标头用于描述资源或服务器或客户端的行为。标头字段保存在 IANA 注册表中。IANA 也维护一个建议的新 HTTP 消息标头的注册表。
HTTP 请求方法
可以使用 HTTP:GET、POST 方法来完成不同操作,或是一些不太常见的请求方式,像是:OPTIONS、DELETE 或 TRACE。
HTTP 状态码
HTTP 状态码用来表示指定的 HTTP 请求是否已成功完成。响应分为五类:信息响应、成功响应,重定向、客户端错误和服务器错误。
CSP 指令
Content-Security-Policy 响应标头字段允许网站管理员控制页面上哪些资源能够被用户代理程序加载。除了少数例外,此策略主要涉及指定服务器来源和脚本终端。
Firefox 开发者工具
Mozilla Observatory
RedBot
用于检查与缓存相关的 HTTP 标头的工具。
浏览器的工作原理(2011)
一篇非常全面的关于浏览器内部实现与通过 HTTP 协议的请求流的文章。可以说是所有 Web 开发者的必读内容。