RFC 9110
HTTP Semantics —— 所有 HTTP 版本共用的方法、状态码、字段与路由语义。报文怎么在线上排,不在这一篇。
:authority 谁在什么版本里 obligatory,并能把状态码第一位当成类、把未识别码归到 x00。标准化方法一览
This specification defines a number of standardized methods that are
commonly used in HTTP, as outlined by the following table.
+=========+============================================+=========+
| Method | Description | Section |
| Name | | |
+=========+============================================+=========+
| GET | Transfer a current representation of the | 9.3.1 |
| | target resource. | |
+---------+--------------------------------------------+---------+
| HEAD | Same as GET, but do not transfer the | 9.3.2 |
| | response content. | |
+---------+--------------------------------------------+---------+
| POST | Perform resource-specific processing on | 9.3.3 |
| | the request content. | |
+---------+--------------------------------------------+---------+
| PUT | Replace all current representations of the | 9.3.4 |
| | target resource with the request content. | |
+---------+--------------------------------------------+---------+
| DELETE | Remove all current representations of the | 9.3.5 |
| | target resource. | |
+---------+--------------------------------------------+---------+
| CONNECT | Establish a tunnel to the server | 9.3.6 |
| | identified by the target resource. | |
+---------+--------------------------------------------+---------+
| OPTIONS | Describe the communication options for the | 9.3.7 |
| | target resource. | |
+---------+--------------------------------------------+---------+
| TRACE | Perform a message loop-back test along the | 9.3.8 |
| | path to the target resource. | |
+---------+--------------------------------------------+---------+
Table 4
[……All general-purpose servers MUST support GET and HEAD]
All general-purpose servers MUST support the methods GET and HEAD. All other methods are OPTIONAL. The set of methods allowed by a target resource can be listed in an Allow header field (Section 10.2.1). However, the set of allowed methods can change dynamically. An origin server that receives a request method that is unrecognized or not implemented SHOULD respond with the 501 (Not Implemented) status code. An origin server that receives a request method that is recognized and implemented, but not allowed for the target resource, SHOULD respond with the 405 (Method Not Allowed) status code.
注解
9110 收的是所有 HTTP 版本共用的语义,不是 HTTP/1.1 报文格式(那是 RFC 9112)也不是 HTTP/2 帧(RFC 9113)。7230 的语义进入 9110,HTTP/1.1 消息语法进入 9112。方法名大小写敏感,登记方法按惯例全大写。
通用源服务器 MUST 实现 GET 和 HEAD。未知或未实现的方法,origin SHOULD 回 501;已实现但不允许用于该目标资源,SHOULD 回 405。发 405 时 MUST 带 Allow(§9.1 / §10.2.1 / §15.5.6)。
安全方法:客户端没请求改状态
Request methods are considered "safe" if their defined semantics are essentially read-only; i.e., the client does not request, and does not expect, any state change on the origin server as a result of applying a safe method to a target resource. Likewise, reasonable use of a safe method is not expected to cause any harm, loss of property, or unusual burden on the origin server. This definition of safe methods does not prevent an implementation from including behavior that is potentially harmful, that is not entirely read-only, or that causes side effects while invoking a safe method. What is important, however, is that the client did not request that additional behavior and cannot be held accountable for it. For example, most servers append request information to access log files at the completion of every response, regardless of the method, and that is considered safe even though the log storage might become full and cause the server to fail. Likewise, a safe request initiated by selecting an advertisement on the Web will often have the side effect of charging an advertising account. Of the request methods defined by this specification, the GET, HEAD, OPTIONS, and TRACE methods are defined to be safe. The purpose of distinguishing between safe and unsafe methods is to allow automated retrieval processes (spiders) and cache performance optimization (pre-fetching) to work without fear of causing harm. In addition, it allows a user agent to apply appropriate constraints on the automated use of unsafe methods when processing potentially untrusted content. A user agent SHOULD distinguish between safe and unsafe methods when presenting potential actions to a user, such that the user can be made aware of an unsafe action before it is requested. When a resource is constructed such that parameters within the target URI have the effect of selecting an action, it is the resource owner's responsibility to ensure that the action is consistent with the request method semantics. For example, it is common for Web- based content editing software to use actions within query parameters, such as "page?do=delete". If the purpose of such a resource is to perform an unsafe action, then the resource owner MUST disable or disallow that action when it is accessed using a safe request method. Failure to do so will result in unfortunate side effects when automated processes perform a GET on every URI reference for the sake of link maintenance, pre-fetching, building a search index, etc.
注解
原文把 safe 定义成:方法的规定语义本质上是只读——客户端不请求、也不期望源服务器因这次请求而改状态。本规范里 GET、HEAD、OPTIONS、TRACE 是 safe。
易误解:safe ≠ 实现没有副作用。规范紧接着写:这个定义并不阻止实现去做有害、非只读、或带副作用的事(写访问日志、广告计费)。关键是客户端没有请求那些额外行为,也不能为此负责。
区分 safe / unsafe 是为了让爬虫和预取敢于自动发请求。把删除做成 GET /page?do=delete 是资源所有者的责任事故。
幂等:多发一次和只发一次,意图效果相同
A request method is considered "idempotent" if the intended effect on the server of multiple identical requests with that method is the same as the effect for a single such request. Of the request methods defined by this specification, PUT, DELETE, and safe request methods are idempotent. Like the definition of safe, the idempotent property only applies to what has been requested by the user; a server is free to log each request separately, retain a revision control history, or implement other non-idempotent side effects for each idempotent request. Idempotent methods are distinguished because the request can be repeated automatically if a communication failure occurs before the client is able to read the server's response. For example, if a client sends a PUT request and the underlying connection is closed before any response is received, then the client can establish a new connection and retry the idempotent request. It knows that repeating the request will have the same intended effect, even if the original request succeeded, though the response might differ. A client SHOULD NOT automatically retry a request with a non- idempotent method unless it has some means to know that the request semantics are actually idempotent, regardless of the method, or some means to detect that the original request was never applied. For example, a user agent can repeat a POST request automatically if it knows (through design or configuration) that the request is safe for that resource. Likewise, a user agent designed specifically to operate on a version control repository might be able to recover from partial failure conditions by checking the target resource revision(s) after a failed connection, reverting or fixing any changes that were partially applied, and then automatically retrying the requests that failed. Some clients take a riskier approach and attempt to guess when an automatic retry is possible. For example, a client might automatically retry a POST request if the underlying transport connection closed before any part of a response is received, particularly if an idle persistent connection was used. A proxy MUST NOT automatically retry non-idempotent requests. A client SHOULD NOT automatically retry a failed automatic retry.
注解
幂等看的是多次相同请求对服务器的意图效果是否等于一次。本规范里 PUT、DELETE,以及所有 safe 方法,都是幂等的。POST 默认不是。
易误解:幂等 ≠ 安全。PUT 幂等但不安全(它请求改状态)。safe 方法一定幂等,反过来不成立。
幂等也不等于实现没有日志、没有版本历史。和 safe 一样,只约束“用户请求了什么”。通信在读到响应前失败时,客户端可以自动重试幂等方法;意图效果相同,不保证响应相同。代理 MUST NOT 自动重试非幂等请求。
IANA 方法登记:Safe / Idempotent
| Method | Safe | Idempotent | Section |
+=========+======+============+=========+
| CONNECT | no | no | 9.3.6 |
+---------+------+------------+---------+
| DELETE | no | yes | 9.3.5 |
+---------+------+------------+---------+
| GET | yes | yes | 9.3.1 |
+---------+------+------------+---------+
| HEAD | yes | yes | 9.3.2 |
+---------+------+------------+---------+
| OPTIONS | yes | yes | 9.3.7 |
+---------+------+------------+---------+
| POST | no | no | 9.3.3 |
+---------+------+------------+---------+
| PUT | no | yes | 9.3.4 |
+---------+------+------------+---------+
| TRACE | yes | yes | 9.3.8 |
+---------+------+------------+---------+
| * | no | no | 18.2 |
+---------+------+------------+---------+
Table 7
注解
对照表:GET / HEAD / OPTIONS / TRACE = safe 且 idempotent;PUT / DELETE = 不安全但幂等;POST / CONNECT = 两者都不是。通配符 * 不能当方法名。
谁带主机名
The "Host" header field in a request provides the host and port
information from the target URI, enabling the origin server to
distinguish among resources while servicing requests for multiple
host names.
In HTTP/2 [HTTP/2] and HTTP/3 [HTTP/3], the Host header field is, in
some cases, supplanted by the ":authority" pseudo-header field of a
request's control data.
Host = uri-host [ ":" port ] ; Section 4
The target URI's authority information is critical for handling a
request. A user agent MUST generate a Host header field in a request
unless it sends that information as an ":authority" pseudo-header
field. A user agent that sends Host SHOULD send it as the first
field in the header section of a request.
For example, a GET request to the origin server for
<http://www.example.org/pub/WWW/> would begin with:
GET /pub/WWW/ HTTP/1.1
Host: www.example.org
注解
用户代理 MUST 生成 Host,除非它改用 :authority 伪首部送同一份权威信息。HTTP/2 与 HTTP/3 里,Host 在部分情形被 :authority 取代;两者表达的是同一件应用层路由信息。
HTTP/1.1 没有 Host 的请求是不合格的。HTTP/2 客户端直接发请求时 MUST 用 :authority(没有权威信息则 MUST NOT 生成它),且 Host 不得与 :authority 指向不同实体——细则在 RFC 9113 §8.3.1。
GET、POST、PUT 的意图差在哪
The GET method requests transfer of a current selected representation for the target resource. A successful response reflects the quality of "sameness" identified by the target URI (Section 1.2.2 of [URI]). Hence, retrieving identifiable information via HTTP is usually performed by making a GET request on an identifier associated with the potential for providing that information in a 200 (OK) response.
[……节选 GET 其余段落,下接 POST]
The POST method requests that the target resource process the
representation enclosed in the request according to the resource's
own specific semantics. For example, POST is used for the following
functions (among others):
* Providing a block of data, such as the fields entered into an HTML
form, to a data-handling process;
* Posting a message to a bulletin board, newsgroup, mailing list,
blog, or similar group of articles;
* Creating a new resource that has yet to be identified by the
origin server; and
* Appending data to a resource's existing representation(s).
[……节选 POST 响应语义,下接 PUT]
The PUT method requests that the state of the target resource be created or replaced with the state defined by the representation enclosed in the request message content. A successful PUT of a given representation would suggest that a subsequent GET on that same target resource will result in an equivalent representation being sent in a 200 (OK) response. However, there is no guarantee that such a state change will be observable, since the target resource might be acted upon by other user agents in parallel, or might be subject to dynamic processing by the origin server, before any subsequent GET is received. A successful response only implies that the user agent's intent was achieved at the time of its processing by the origin server.
[……节选 PUT 约束与校验器,下接与 POST 的对照]
The fundamental difference between the POST and PUT methods is highlighted by the different intent for the enclosed representation. The target resource in a POST request is intended to handle the enclosed representation according to the resource's own semantics, whereas the enclosed representation in a PUT request is defined as replacing the state of the target resource. Hence, the intent of PUT is idempotent and visible to intermediaries, even though the exact effect is only known by the origin server.
注解
GET 请求传送目标资源当前选定的表示,不是“下载服务器上那个文件”。同一 URI 的“同一性”由资源自己定义。
POST 请目标资源按它自己的语义处理请求里的表示:提交表单、发帖、创建尚未命名的资源、追加数据,都是合法例子。由哪一个状态码描述结果,也由这次处理决定。
PUT 请求用附带表示创建或替换目标资源的状态。成功的 PUT 暗示随后 GET 会得到等价表示,但不保证——别人可能并行改,服务器也可能动态加工。
对照句是考点:POST 的目标负责“处理”表示;PUT 的表示被定义为“替换目标状态”。所以 PUT 的意图幂等,且对中间件可见。
三位数字与五类
The status code of a response is a three-digit integer code that
describes the result of the request and the semantics of the
response, including whether the request was successful and what
content is enclosed (if any). All valid status codes are within the
range of 100 to 599, inclusive.
The first digit of the status code defines the class of response.
The last two digits do not have any categorization role. There are
five values for the first digit:
* 1xx (Informational): The request was received, continuing process
* 2xx (Successful): The request was successfully received,
understood, and accepted
* 3xx (Redirection): Further action needs to be taken in order to
complete the request
* 4xx (Client Error): The request contains bad syntax or cannot be
fulfilled
* 5xx (Server Error): The server failed to fulfill an apparently
valid request
[……下接可扩展性与非法值]
HTTP status codes are extensible. A client is not required to understand the meaning of all registered status codes, though such understanding is obviously desirable. However, a client MUST understand the class of any status code, as indicated by the first digit, and treat an unrecognized status code as being equivalent to the x00 status code of that class. For example, if a client receives an unrecognized status code of 471, it can see from the first digit that there was something wrong with its request and treat the response as if it had received a 400 (Bad Request) status code. The response message will usually contain a representation that explains the status. Values outside the range 100..599 are invalid. Implementations often use three-digit integer values outside of that range (i.e., 600..999) for internal communication of non-HTTP status (e.g., library errors). A client that receives a response with an invalid status code SHOULD process the response as if it had a 5xx (Server Error) status code.
[……下接 IANA 登记表 Table 8]
| Value | Description | Section |
+=======+===============================+=========+
| 100 | Continue | 15.2.1 |
+-------+-------------------------------+---------+
| 101 | Switching Protocols | 15.2.2 |
+-------+-------------------------------+---------+
| 200 | OK | 15.3.1 |
+-------+-------------------------------+---------+
| 201 | Created | 15.3.2 |
+-------+-------------------------------+---------+
| 202 | Accepted | 15.3.3 |
+-------+-------------------------------+---------+
| 203 | Non-Authoritative Information | 15.3.4 |
+-------+-------------------------------+---------+
| 204 | No Content | 15.3.5 |
+-------+-------------------------------+---------+
| 205 | Reset Content | 15.3.6 |
+-------+-------------------------------+---------+
| 206 | Partial Content | 15.3.7 |
+-------+-------------------------------+---------+
| 300 | Multiple Choices | 15.4.1 |
+-------+-------------------------------+---------+
| 301 | Moved Permanently | 15.4.2 |
+-------+-------------------------------+---------+
| 302 | Found | 15.4.3 |
+-------+-------------------------------+---------+
| 303 | See Other | 15.4.4 |
+-------+-------------------------------+---------+
| 304 | Not Modified | 15.4.5 |
+-------+-------------------------------+---------+
| 305 | Use Proxy | 15.4.6 |
+-------+-------------------------------+---------+
| 306 | (Unused) | 15.4.7 |
+-------+-------------------------------+---------+
| 307 | Temporary Redirect | 15.4.8 |
+-------+-------------------------------+---------+
| 308 | Permanent Redirect | 15.4.9 |
+-------+-------------------------------+---------+
| 400 | Bad Request | 15.5.1 |
+-------+-------------------------------+---------+
| 401 | Unauthorized | 15.5.2 |
+-------+-------------------------------+---------+
| 402 | Payment Required | 15.5.3 |
+-------+-------------------------------+---------+
| 403 | Forbidden | 15.5.4 |
+-------+-------------------------------+---------+
| 404 | Not Found | 15.5.5 |
+-------+-------------------------------+---------+
| 405 | Method Not Allowed | 15.5.6 |
+-------+-------------------------------+---------+
| 406 | Not Acceptable | 15.5.7 |
+-------+-------------------------------+---------+
| 407 | Proxy Authentication Required | 15.5.8 |
+-------+-------------------------------+---------+
| 408 | Request Timeout | 15.5.9 |
+-------+-------------------------------+---------+
| 409 | Conflict | 15.5.10 |
+-------+-------------------------------+---------+
| 410 | Gone | 15.5.11 |
+-------+-------------------------------+---------+
| 411 | Length Required | 15.5.12 |
+-------+-------------------------------+---------+
| 412 | Precondition Failed | 15.5.13 |
+-------+-------------------------------+---------+
| 413 | Content Too Large | 15.5.14 |
+-------+-------------------------------+---------+
| 414 | URI Too Long | 15.5.15 |
+-------+-------------------------------+---------+
| 415 | Unsupported Media Type | 15.5.16 |
+-------+-------------------------------+---------+
| 416 | Range Not Satisfiable | 15.5.17 |
+-------+-------------------------------+---------+
| 417 | Expectation Failed | 15.5.18 |
+-------+-------------------------------+---------+
| 418 | (Unused) | 15.5.19 |
+-------+-------------------------------+---------+
| 421 | Misdirected Request | 15.5.20 |
+-------+-------------------------------+---------+
| 422 | Unprocessable Content | 15.5.21 |
+-------+-------------------------------+---------+
| 426 | Upgrade Required | 15.5.22 |
+-------+-------------------------------+---------+
| 500 | Internal Server Error | 15.6.1 |
+-------+-------------------------------+---------+
| 501 | Not Implemented | 15.6.2 |
+-------+-------------------------------+---------+
| 502 | Bad Gateway | 15.6.3 |
+-------+-------------------------------+---------+
| 503 | Service Unavailable | 15.6.4 |
+-------+-------------------------------+---------+
| 504 | Gateway Timeout | 15.6.5 |
+-------+-------------------------------+---------+
| 505 | HTTP Version Not Supported | 15.6.6 |
+-------+-------------------------------+---------+
Table 8
注解
合法范围 100–599。只看第一位分类:1 继续、2 成功、3 要再动作、4 请求有问题、5 服务器没完成一个看起来合法的请求。后两位没有再分类的规范角色。
客户端 MUST 理解“类”,不认识的码按该类的 x00 处理:471 当 400。100–599 以外的值非法,收到后 SHOULD 当 5xx。实现内部用 600–999 当库错误,那不是 HTTP 状态码。
reason phrase 只是建议,可以换成本地语言或省略。一次请求可以有零个或多个 1xx 中间响应,然后恰好一个最终响应。
表里 418 仍登记为 Unused(不再是“我是茶壶”玩笑码的规范位置)。421 是 Misdirected Request,和前面 Host / 权威信息不匹配那节对应。
抓包对照
语义字段落在请求行 / 状态行和首部里。HTTP/1.1 明文(或 TLS 解密后)最容易对上这一篇;HTTP/2 over HTTPS 的常见路径是 ALPN h2,解密后再把伪首部映射回同一套方法与状态码。明文 TCP 上的 h2 只能靠 prior knowledge(RFC 9113 §3.3),不能靠 Upgrade。
- 方法 / 状态码的语义跨版本一致;HTTP/1.1 在文本起始行可直接看到,HTTP/2 需解压 HPACK 字段块后见
:method/:status伪首部,不能假设线上原始字节是 ASCII。 - HTTPS 上先看到 TLS;没有密钥就看不到 9110 这些字段。对照本页请用明文 80 或已解密的 443。
- 不要在 HTTP/2 里找必须出现的
Host:行。先看:authority;Host 若在,不得和它指向不同实体。 - HEAD 的响应有首部、无内容。抓包长度对不上 GET,是规范行为,不是截断。
考点与易错点
- safe 指客户端不请求、不期望状态变化;实现仍可写日志、计费。safe ≠ 无副作用。
- 幂等指多次相同请求的意图效果等于一次。PUT / DELETE 幂等但不安全;POST 默认两者都不是。
- 幂等不是“可以随便重试 POST”。代理 MUST NOT 自动重试非幂等请求。
- GET 传送当前选定表示,不是读磁盘文件。POST 按资源自己的语义处理表示;PUT 替换目标资源状态。
- 用户代理必须送 Host,除非改送
:authority。HTTP/2 / HTTP/3 里后者在部分情形取代前者。 - 状态码 100–599;不认识的码按该类 x00;范围外非法,客户端 SHOULD 按 5xx 处理。reason phrase 可省略。