HTTP状态码参考
浏览HTTP状态码及其说明。
| Code | Name | Class | Meaning |
|---|---|---|---|
| 100 | Continue | Informational | The client should continue with its request. |
| 101 | Switching Protocols | Informational | The server is switching protocols as requested. |
| 200 | OK | Success | The request succeeded. |
| 201 | Created | Success | The request succeeded and a new resource was created. |
| 202 | Accepted | Success | The request was accepted but not yet processed. |
| 204 | No Content | Success | Success, but there is no content to return. |
| 206 | Partial Content | Success | The server delivered part of the resource (range request). |
| 301 | Moved Permanently | Redirection | The resource has permanently moved to a new URL. |
| 302 | Found | Redirection | The resource is temporarily at a different URL. |
| 304 | Not Modified | Redirection | The cached version is still valid. |
| 307 | Temporary Redirect | Redirection | Temporary redirect that preserves the method. |
| 308 | Permanent Redirect | Redirection | Permanent redirect that preserves the method. |
| 400 | Bad Request | Client Error | The server could not understand the request. |
| 401 | Unauthorized | Client Error | Authentication is required and has failed or not been provided. |
| 403 | Forbidden | Client Error | The server understood but refuses to authorize the request. |
| 404 | Not Found | Client Error | The requested resource could not be found. |
| 405 | Method Not Allowed | Client Error | The HTTP method is not supported for this resource. |
| 408 | Request Timeout | Client Error | The server timed out waiting for the request. |
| 409 | Conflict | Client Error | The request conflicts with the current state of the resource. |
| 410 | Gone | Client Error | The resource is permanently gone. |
| 418 | I'm a teapot | Client Error | An April Fools joke from RFC 2324. |
| 422 | Unprocessable Entity | Client Error | The request was well-formed but semantically invalid. |
| 429 | Too Many Requests | Client Error | The client has sent too many requests (rate limited). |
| 500 | Internal Server Error | Server Error | A generic server-side error occurred. |
| 501 | Not Implemented | Server Error | The server does not support the requested functionality. |
| 502 | Bad Gateway | Server Error | An upstream server returned an invalid response. |
| 503 | Service Unavailable | Server Error | The server is temporarily overloaded or down. |
| 504 | Gateway Timeout | Server Error | An upstream server did not respond in time. |
概述
状态码是服务器对「发生了什么」给出的一句话总结,而挑错一个的后果,远不只是显得不够整洁而已:它会改变客户端是否重试、缓存是否存储这个响应、爬虫是否继续保留这个 URL,以及代理会不会把这个请求再处理一次。
这是一份可搜索的参考,覆盖的是你实际会遇到的那些状态码,而每一条给出的都是实用的区分要点,而不是把规范原文重述一遍。
使用方法
输入一个数字(404)或者名称的一部分(gateway)来过滤清单。匹配同时作用于这两个字段,所以 too many 和 429 会找到同一条。
五个类别
| 类别 | 含义 | 客户端该怎么做 |
|---|---|---|
1xx | 信息性——请求仍在进行中 | 继续等 |
2xx | 成功 | 使用这个响应 |
3xx | 重定向——资源在别处,或者根本没有变化 | 跟过去,或者用缓存 |
4xx | 客户端错误——请求本身就是问题所在 | 不要原样重试 |
5xx | 服务器错误——请求本身可能没有问题 | 带退避地重试 |
4xx 和 5xx 之间的划分在实践中是最要紧的一条,因为它直接决定了重试行为。一台对畸形请求返回 500 的服务器,会被每一个带重试策略的守规矩客户端一遍又一遍地送来同一个畸形请求。只有返回 400 才能终止这个循环。
值得分清的那些区别
200 加一个装在正文里的错误。 这在 API 里很常见,而且几乎总是错的。你和客户端之间的每一层——缓存、代理、监控、重试逻辑——读的都是状态码,而不是你的 JSON。一个返回 200 的错误,对它们全都是不可见的。
创建时该用 201 还是 200。 201 应该携带一个指向新资源的 Location 头。那才是客户端真正会用到的部分;单独一个状态码本身添的东西不多。
202 Accepted。 对于那些你排进队列而不是当场做完的工作,这是正确的答案。它是一个承诺,所以它需要告诉客户端去哪里查询进展——一个状态 URL,或者一个任务 id。
204 No Content。 表示成功,并且刻意不带正文,典型场景是 DELETE,或者一个不返回任何内容的 PUT。它必须完全没有正文,而不是一个空的 JSON 对象。
304 Not Modified。 这是对一个条件请求的响应,其 ETag 或 Last-Modified 仍然匹配。它不带正文,而这正是它的全部意义所在:客户端已经有那些字节了。如果你从来不返回 304,那么每一次重新验证都会把整个资源再传一遍。
400 还是 422。 400 用于服务器根本无法解析的请求——畸形的 JSON、缺少某个必需参数。422 用于那些解析得干干净净、但校验失败的请求。这个区分告诉客户端,它该去修的是自己的序列化,还是自己的数据。
405 Method Not Allowed。 必须包含一个 Allow 头,列出哪些方法是被接受的。没有它,客户端只是被拒绝了,却拿不到任何前进的路径。
409 Conflict。 用于那些无法应用到当前状态的请求——针对一个过期版本的编辑、一个违反唯一约束的重复项。它不是一个泛用的「有什么地方不对」。
410 Gone。 一个更强的 404:这个东西曾经存在,而且不会回来了。爬虫丢掉 410 比丢掉 404 更快,而对于你刻意移除的内容来说,这正是你想要的效果。
429 Too Many Requests。 需要配上 Retry-After。没有它,客户端只能靠猜,而且会猜得很糟——通常就是立刻重试。
502、503 和 504 之间的区别。 502 意味着某个上游返回了一个无效的响应。503 意味着这台服务器自己不可用,典型的情况是过载或者正在维护。504 意味着某个上游没有及时给出应答。它们指向的是三个完全不同的地方,而把它们互换着用,会让一次故障变得更难定位。
示例
- 爬虫一直在请求一个已经删除的页面。 返回
410而不是404。 - 客户端在猛敲一个正在失败的端点。 检查这个失败是不是把实际上属于
4xx的情况返回成了5xx。 - 一次表单提交在重定向之后把数据丢了。 这个重定向大概是
301或302;改成308或307。 - CDN 不肯缓存某个响应。
2xx和3xx默认是可缓存的;大多数4xx不可缓存,而5xx永远都不该被缓存。 - 一个 API 返回
200,客户端无视了失败。 它们不是在无视——根本就没有东西告诉过它们。
说明
418 I'm a teapot 是真实存在的,在「它已被登记并且被永久保留」这个意义上。它出自一份愚人节的 RFC,之所以出现在这份清单里,是因为人们真的会去查它。
不在登记表里的状态码同样是合法的。客户端必须按类别去处理任何一个未知的状态码,所以一个自定义的 299 会被当成成功,而一个自定义的 599 会被当成服务器错误。真要去用它们,通常并不值得换来那份困惑。
这里的清单覆盖的是实际还在使用中的那些状态码。完整的登记表由 IANA 维护,其中还包含 WebDAV 以及其他扩展所用的状态码,而一个典型的 Web 服务永远都不会返回它们。
想看某个线上 URL 实际返回哪些状态码,包括它的整条重定向链,请用 HTTP 头信息检查。