3. 术语和核心概念
HTTP 为 World Wide Web (WWW) 架构而创建, 并随着时间演进, 以支持全球性超文本系统的可扩展性需求. 该架构的许多内容都反映在用于定义 HTTP 的术语中.
3.1. 资源
HTTP 请求的目标称为 "资源" (resource). HTTP 不限制资源的性质; 它只是定义了一个可用于与资源交互的接口. 大多数资源由 Uniform Resource Identifier (URI) 标识, 如 Section 4 所述.
HTTP 的一个设计目标是将资源标识与请求语义分离, 这是通过把请求语义赋予请求方法 (Section 9) 和少数会修改请求的头字段来实现的. 资源不能以与请求方法语义不一致的方式处理请求. 例如, 虽然某个资源的 URI 可能暗示不安全的语义, 但客户端可以期望该资源在处理使用安全方法的请求时避免不安全动作 (见 Section 9.2.1).
HTTP 依赖 Uniform Resource Identifier (URI) 标准 [URI] 来指示目标资源 (Section 7.1) 以及资源之间的关系.
3.2. 表示
"表示" (representation) 是指意图反映给定资源过去, 当前或期望状态的信息, 其格式能够通过协议方便地通信. 一个表示由一组表示元数据和一个可能无界的表示数据流组成 (Section 8).
HTTP 通过围绕资源状态的可传输表示来定义通信, 而不是传输资源本身, 从而允许在其统一接口背后进行 "信息隐藏".这使 URI 所标识的资源可以是任何事物, 包括像 "Laguna Beach 当前天气" 这样的时间函数, 同时仍可在消息生成时提供表示该资源的信息 [REST].
统一接口类似一扇窗口, 人们只能通过向另一侧的独立参与者发送消息来观察某物并对其采取动作. 在我们的通信中, 需要一个共享抽象来表示 (即 "代替") 该事物的当前状态或期望状态. 当表示是超文本时, 它既可以提供资源状态的表示, 也可以提供有助于引导接收方未来交互的处理指令.
目标资源可能被提供多个表示, 或者能够生成多个表示, 每个表示都意图反映该资源的当前状态. 通常会使用一个基于内容协商 (Section 12) 的算法, 从这些表示中选择一个最适用于给定请求的表示. 这个 "选定表示" (selected representation) 提供用于评估条件请求 (Section 13) 的数据和元数据, 并用于构造对 GET (Section 9.3.1) 的 200 (OK),206 (Partial Content) 和 304 (Not Modified) 响应内容.
3.3. 连接, 客户端和服务器
HTTP 是一种客户端/服务器协议, 运行在可靠的传输层或会话层 "连接" (connection) 之上.
HTTP "客户端" (client) 是为了发送一个或多个 HTTP 请求而建立到服务器连接的程序. HTTP "服务器" (server) 是接受连接并通过发送 HTTP 响应来服务 HTTP 请求的程序.
术语客户端和服务器仅指这些程序在特定连接上执行的角色. 同一个程序可能在某些连接上充当客户端, 在另一些连接上充当服务器.
HTTP 被定义为无状态协议, 这意味着每个请求消息的语义都可以单独理解, 且连接与其上传输的消息之间的关系不会影响这些消息的解释. 例如, CONNECT 请求 (Section 9.3.6) 或带有 Upgrade 头字段 (Section 7.8) 的请求可以在任何时候出现, 而不仅限于连接上的第一个消息. 许多实现依赖 HTTP 的无状态设计, 以便复用代理连接或在多个服务器之间动态负载均衡请求.
因此, 除非连接已经安全保护并且专用于该用户代理, 服务器不得假定同一连接上的两个请求来自同一个用户代理. 一些非标准 HTTP 扩展 (例如 [RFC4559]) 已知会违反此要求, 从而导致安全和互操作性问题.
3.4. 消息
HTTP 是一种无状态请求/响应协议, 用于跨连接交换 "消息" (message). 术语 "发送方" (sender) 和 "接收方" (recipient) 分别指发送或接收给定消息的任何实现.
客户端以 "请求" (request) 消息的形式向服务器发送请求, 其中包含方法 (Section 9) 和请求目标 (Section 7.1). 该请求还可能包含头字段 (Section 6.3), 用于请求修饰符, 客户端信息和表示元数据; 包含意图按该方法处理的内容 (Section 6.4); 以及包含用于传达发送内容期间收集信息的尾字段 (Section 6.5).
服务器通过发送一个或多个 "响应" (response) 消息来回应客户端请求, 每个响应都包含状态码 (Section 15). 响应还可能包含用于服务器信息, 资源元数据和表示元数据的头字段; 包含按状态码解释的内容; 以及包含用于传达发送内容期间收集信息的尾字段.
3.5. 用户代理
术语 "用户代理" (user agent) 指发起请求的各种客户端程序.
最常见的用户代理形式是通用 Web 浏览器, 但这只是实现中的一小部分. 其他常见用户代理包括蜘蛛程序 (遍历 Web 的机器人), 命令行工具, 公告屏, 家用电器, 秤,灯泡, 固件更新脚本, 移动应用, 以及形态和尺寸各异的通信设备.
作为用户代理并不意味着在请求发生时一定有真人用户正在直接与该软件代理交互. 在许多情况下, 用户代理被安装或配置为在后台运行, 并保存其结果以供日后检查 (或者只保存其中可能有趣或错误的子集). 例如, 蜘蛛程序通常会获得一个起始 URI, 并被配置为在把 Web 作为超文本图进行爬取时遵循某些行为.
许多用户代理不能, 或选择不向其用户提供交互式建议, 也不能或选择不为安全或隐私问题提供充分警告. 在本规范少数要求向用户报告错误的情况下, 只要这种报告能在错误控制台或日志文件中被观察到, 就是可以接受的. 同样, 要求自动动作在继续前由用户确认, 可以通过预先配置选择, 运行时选项或简单地避免不安全动作来满足; 如果用户已经做出该选择, 确认并不意味着任何特定用户界面或对正常处理的中断.
3.6. 源服务器
术语 "源服务器" (origin server) 指能够为给定目标资源发起权威响应的程序.
最常见的源服务器形式是大型公共网站. 然而, 正如把用户代理等同于浏览器会造成误导一样, 认为所有源服务器都相同也很容易误导人. 常见源服务器还包括家庭自动化单元, 可配置网络组件, 办公设备, 自主机器人, 新闻源, 交通摄像头, 实时广告选择器和视频点播平台.
大多数 HTTP 通信由针对 URI 所标识某个资源表示的检索请求 (GET) 组成. 在最简单情况下, 这可以通过用户代理 (UA) 与源服务器 (O) 之间的单个双向连接 (===) 完成.
request >
UA ======================================= O
< response
图 1
3.7. 中介
HTTP 允许使用中介通过连接链满足请求. HTTP "中介" (intermediary) 有三种常见形式: 代理, 网关和隧道. 在某些情况下, 单个中介可能根据每个请求的性质切换行为, 充当源服务器, 代理, 网关或隧道.
> > > >
UA =========== A =========== B =========== C =========== O
< < < <
图 2
上图显示了用户代理和源服务器之间的三个中介 (A, B 和 C). 沿整个链传输的请求或响应消息将经过四个独立连接. 有些 HTTP 通信选项可能只适用于与最近的非隧道邻居之间的连接, 只适用于链的端点, 或适用于链上的所有连接. 虽然图示是线性的, 但每个参与者都可能同时参与多个通信. 例如, B 在处理 A 的请求时, 可能同时接收来自 A 以外许多客户端的请求, 和/或把请求转发到 C 以外的服务器. 同样, 后续请求可能通过不同的连接路径发送, 这通常基于用于负载均衡的动态配置.
术语 "上游" (upstream) 和 "下游" (downstream) 用于相对于消息流描述方向性要求: 所有消息都从上游流向下游. 术语 "入站" (inbound) 和 "出站" (outbound) 用于相对于请求路由描述方向性要求: 入站表示 "朝向源服务器", 出站表示 "朝向用户代理".
"代理" (proxy) 是由客户端选择的消息转发代理, 通常通过本地配置规则选择, 用于接收某些类型绝对 URI 的请求, 并尝试通过 HTTP 接口转换来满足这些请求. 有些转换很小, 例如针对 "http" URI 的代理请求, 而其他请求可能需要在完全不同的应用层协议之间进行转换. 代理常用于让组织的 HTTP 请求经由公共中介集中处理, 以提供安全服务, 注释服务或共享缓存. 有些代理被设计为在转发过程中对选定消息或内容应用转换, 如 Section 7.7 所述.
"网关" (gateway, 也称 "反向代理") 是一种中介, 它在出站连接上充当源服务器, 但会转换收到的请求并将其入站转发到另一个或多个服务器. 网关常用于封装遗留或不受信任的信息服务, 通过 "加速器" 缓存提高服务器性能, 并支持跨多台机器对 HTTP 服务进行分区或负载均衡.
所有适用于源服务器的 HTTP 要求也适用于网关的出站通信. 网关可以使用其希望使用的任何协议与入站服务器通信, 包括超出本规范范围的 HTTP 私有扩展. 然而, 希望与第三方 HTTP 服务器互操作的 HTTP-to-HTTP 网关, 需要在网关的入站连接上符合用户代理要求.
"隧道" (tunnel) 在两个连接之间充当盲中继, 不改变消息. 一旦激活, 隧道就不再被视为 HTTP 通信的一方, 尽管隧道可能由 HTTP 请求发起. 当被中继连接的两端都关闭时, 隧道即停止存在. 隧道用于通过中介扩展虚拟连接, 例如使用 Transport Layer Security (TLS, [TLS13]) 通过共享防火墙代理建立机密通信时.
上述中介类别只考虑作为 HTTP 通信参与者的中介. 还有一些中介可以在网络协议栈的较低层上运行, 在消息发送方不知情或未许可的情况下过滤或重定向 HTTP 流量. 网络中介在协议层面上与路径上的攻击者无法区分, 并且常因错误违反 HTTP 语义而引入安全缺陷或互操作性问题.
例如, "拦截代理" (interception proxy) [RFC3040] (也常称为 "透明代理" (transparent proxy) [RFC1919]) 与 HTTP 代理不同, 因为它不是由客户端选择的. 相反, 拦截代理会过滤或重定向发出的 TCP 端口 80 数据包 (有时也包括其他常见端口流量). 拦截代理常见于公共网络接入点, 用作在允许使用非本地 Internet 服务前强制执行账号订阅的手段; 也常见于企业防火墙内部, 用于强制执行网络使用策略.
3.8. 缓存
"缓存" (cache) 是先前响应消息的本地存储, 也是控制其消息存储, 检索和删除的子系统. 缓存存储可缓存响应, 以便在未来等价请求中降低响应时间和网络带宽消耗. 任何客户端或服务器都可以使用缓存, 但在充当隧道时不能使用缓存.
缓存的效果是, 如果链上的某个参与者拥有适用于该请求的缓存响应, 则请求/响应链会缩短. 下图说明了当 B 拥有先前经 C 来自 O 的响应缓存副本, 且 UA 或 A 未缓存该请求时得到的链.
> >
UA =========== A =========== B - - - - - - C - - - - - - O
< <
图 3
如果允许缓存存储某个响应消息的副本以用于回答后续请求, 则该响应是 "可缓存的" (cacheable). 即使响应可缓存, 客户端或源服务器也可能对该缓存响应何时可用于特定请求施加额外约束. HTTP 对缓存行为和可缓存响应的要求定义于 [CACHING].
World Wide Web 和大型组织内部部署了多种缓存架构和配置. 这些包括用于节省带宽和降低延迟的全国性代理缓存层级, 使用网关缓存来优化热门站点区域和全球分发的内容分发网络, 广播或组播缓存条目的协作系统, 用于离线或高延迟环境的预取缓存条目归档, 等等.
3.9. 示例消息交换
以下示例展示了针对 URI http://www.example.com/hello.txt 的 GET 请求 (Section 9.3.1) 的典型 HTTP/1.1 消息交换:
客户端请求:
GET /hello.txt HTTP/1.1
User-Agent: curl/7.64.1
Host: www.example.com
Accept-Language: en, mi
服务器响应:
HTTP/1.1 200 OK
Date: Mon, 27 Jul 2009 12:28:53 GMT
Server: Apache
Last-Modified: Wed, 22 Jul 2009 19:15:56 GMT
ETag: "34aa387-d-1568eb00"
Accept-Ranges: bytes
Content-Length: 51
Vary: Accept-Encoding
Content-Type: text/plain
Hello World! My content includes a trailing CRLF.