toolfree

HTTP 状态码

所有 HTTP 状态码,依类别分组,并说明真正容易搞混的那几组:301 与 308、401 与 403、502 与 504。

在你的浏览器中运行

点一下代码即可复制。

1xx · 信息

请求已收到,处理仍在继续。人工很少会看到这一类。

代码意义
Continue可以继续发送请求主体。这是对 `Expect: 100-continue` 标头的回应,让客户端在发送大型上传之前,先确认服务器愿意接收。
Switching Protocols连接正在切换协议,最常见的是切换到 WebSocket。
Early Hints先发送的初步标头,让浏览器能在真正的响应之前先开始抓取资源。
2xx · 成功

请求已收到、已理解,也被接受了。

代码意义
OK成功了。
Created成功了,而且产生了新的资源,地址在 `Location` 标头里。
No Content成功了,而且刻意没有任何内容要回传。204 不能带有主体。硬要发送主体是协议错误,有些客户端会处理得很糟。
Partial Content响应 `Range` 请求所发送的部分内容。视频拖动进度与断点续传就是靠它运作的。
3xx · 重定向

你要的东西在别的地方,或是根本没有变过。

代码意义
Moved Permanently已经永久搬走了,请更新你的链接。301 和 302 允许客户端在重定向时把 POST 换成 GET,而浏览器确实会这么做。如果方法必须保留,请改用 308 或 307。
Found暂时在别的地方,请继续使用原本这个网址。
See Other请改用 GET 去取另一个网址——表单提交完成后最常见的响应。
Not Modified你缓存的版本仍然有效,不会回传主体。
Temporary Redirect暂时在别的地方,而且请求方法不能改变。
Permanent Redirect永久搬到别的地方,而且请求方法不能改变。
4xx · 客户端错误

请求本身有问题,或是不被允许。改变请求内容可能会有帮助。

代码意义
Bad Request服务器根本看不懂这个请求。
Unauthorized你尚未通过身份验证,服务器不知道你是谁。名字取错了:401 的意思是「未验证身份」,「没有权限」是 403。401 必须带上 `WWW-Authenticate` 标头。
Forbidden服务器知道你是谁,但你就是不能拿到这个东西。重新登录没有用。如果连「这个资源存在」本身都算机密,回 404 才是比较安全的做法。
Not Found这个地址上没有任何东西。它完全没有说这东西曾经存不存在。如果你确定它永远消失了,请用 410。
Method Not Allowed这个地址存在,但不接受这个方法。响应必须列出可用的方法。
Conflict请求与目前的状态冲突,例如你正在修改的其实是旧版本。
Gone它曾经存在,而且是刻意被移除的,不会再回来。
I'm a teapot1998 年愚人节的玩笑,然后就再也没消失过。
Unprocessable Content格式没问题,但语义上是错的——例如合法的 JSON 里有不合法的字段。
Too Many Requests你被限流了,`Retry-After` 会告诉你什么时候可以再来。
5xx · 服务器错误

请求本身没有问题,是服务器没能处理好。

代码意义
Internal Server Error出了问题,而服务器说不出更具体的原因。
Not Implemented服务器根本不支持这个要求。
Bad Gateway代理服务器向上游询问,却拿到一个无法使用的响应。上游有响应,只是回得不对。504 是上游没有在时限内响应,503 则是这台服务器自己决定不处理。
Service Unavailable暂时不提供服务,可能是超载或正在维护。
Gateway Timeout代理服务器等待上游响应,最后放弃了。

先看第一个数字

类别会告诉你「问题出在谁身上」,以及「重试有没有意义」:

最后那个区别,在出事时最有用。4xx 表示先停下来检查你送了什么;5xx 表示请求本身没问题, 重试是合理的。

最常被搞混的几组

**401 的名字取错了。**它的意思是尚未验证身分——服务器不知道你是谁——而且必须带上 WWW-Authenticate 头部。「没有权限」是 403。重新登入能解决 401,对 403 完全没用。

**机密资源该回 403 还是 404?**如果「这个资源存在」这件事本身就是机密,回 404 比较安全: 403 等于承认那里确实有东西。

**404 没有说任何关于过去的事。**如果你确定那个东西是被刻意、永久移除的,请用 410——它会 让爬虫停止再来询问。

**502、503、504 是三种不同的失败。**上游回了但回得不对、这台服务器自己决定不处理、上游 没有在时限内回应。

重新导向会换掉你的方法,这一点常让人意外

301 和 302 允许客户端在跟随重新导向时把 POST 换成 GET,而每一个浏览器都确实这么做。 所以如果你用 302 去重新导向一个表单送出,主体在抵达时就已经不见了。

307 和 308 的存在正是为了禁止这件事。它们分别等同于 302 和 301,只是多了一项保证:方法 与主体必须原封不动地保留。只要重新导向可能载着 POST,就用 307 或 308。

303 则是刻意反过来:它告诉客户端改用 GET 去取另一个地址,这正是表单完成后应该给的回应, 让浏览器停在一个可以安全重新整理、而不会重复送出的结果页。

418 是真的存在,某种意义上

418 I'm a teapot 来自 1998 年的愚人节 RFC,然后就再也没消失。它不是真正的状态码,而且 曾经有人提案把它从注册表中移除,却因为实作它的人太多而被否决。服务器偶尔真的会拿它来表示 「我就是不做这件事」。