MDN Web Docs
维基百科

1xx 请求已被接受,需要继续处理

1 打头的其实不是很常用。

不过有一个 102 Processing (WebDAV) 挺有意思,用于表明 WebDAV 服务器收到了请求,但请求的操作比较费时,服务器正在处理(如遍历当前文件夹)。为了防止客户端 TCP 超时、假设请求丢失,于是服务器可以发送一个没有信息的 102 应答。

2xx 请求已被服务器接收、理解、并接受

最常用的就是 200 OK 了,这是绝大多数 GET 方法、以及部分 POST PUT PATCH 成功后的返回值。它表示(一般时获取或修改)请求成功了,应答中会包含 GET 所请求的 Object,或者 POST PUT PATCH 成功后新的 Object。

201 Created 也非常常用,这主要用于 POST 创建一个 Object 这类请求的应答。它表示创建的请求成功了,应答中会包含 Object 的内容,或者应答的 Location 首部会包含这个 Object 的链接。

202 Accepted 表示服务器端已经收到了请求,但是还没有处理。一个非常典型的场景就是用户忘记了密码,申请重置密码。服务器应当发送一份邮件到用户的邮箱,但发送邮箱是一个很慢的过程,因此服务器可以在收到用户的请求后,立即响应 202,同时尝试发送邮件。202 同时意味着,发送邮件到底有没有成功,用户是无法得知的,服务器并不能通过 HTTP 协议告知用户成功与否。再换句话说,就是服务器不保证请求的处理结果。这和 102 有点像,区别在于服务器发送 102 以后,可以稍后再发送一个应答说明情况,而 202 就不能了。

除此之外还有 204 No Content 表示没有返回信息,这是绝大多数 DELETE 方法成功后(以及 PUT 请求更新资源,但是不需要改变当前的用户页面)的返回值。如果想要改变 PUT 请求的用户的当前页面,应当选用 201202

以及 206 Partial Content 表示报文包含的是请求的内容的一部分,这一般用于上传/下载的文件相当大的时候(下载的时候抓一下包就能看到很多的 206)。

3xx 客户端需要进一步操作

通常来说,“进一步操作”就是指的重定向,因此最常用的也就是 301 302 307 308 这四个。

301 Moved Permanently302 Found (或 302 Moved Temporarily)、307 Temporary Redirect308 Permanent Redirect

Stack Overflow 上有一个表格非常形象:

永久重定向 Permanently 暂时重定向 Temporarily
允许将 POST 方法改为 GET 301 Moved Permanently 302 Moved Temporarily
不允许将 POST 方法改为 GET 308 Permanent Redirect 307 Temporary Redirect

何谓 PermanentlyTemporarily?

  • 字面上理解:Permanently 指的是用户访问的网站永久迁移到新网址了,而 Temporarily 指的是用户访问的网站暂时(可能是 24-48 小时内)迁移到新网址;
  • 对于浏览器:
    • 对于 Permanently 的结果,浏览器会缓存 original_urlredirect_url1。下次用户访问 original_url 时,浏览器会直接向 redirect_url1 发送请求(而不会请求 original_url
    • 对于 Temporarily,浏览器不会缓存。下次用户访问 original_url 时,浏览器仍会向 original_url 发送请求
  • 对于搜索引擎:
    • 对于 Permanently 的结果,搜索引擎会记录跳转后的网址和内容;
    • 对于 Temporarily 则有些尴尬,搜索引擎不知道应该记录跳转后还是跳转前的网址(比如 A 网址很短,但是它做了一个 302 重定向到 B 网址,而 B 网址是一个很长的乱七八糟的 URL,甚至还有可能包含一些问号之类的参数。很自然的,A 网址更加用户友好,而 B 网址既难看,又不用户友好;Google 家就选择记录 A 网址)这样就导致了 网址 URL 劫持:B 网站的很好的内容在 Google 上却显示的是网址 A。

所以,尽量选择 Permanently 吧。

除此之外,还有 304 Not Modified,一般是缓存服务器向目标服务器请求,询问请求的资源是否和缓存的版本一致(请求头中加上 If-Modified-Since),服务器返回 304 表示确实没有修改过,这种情况下,由于缓存服务器仍然具有以前下载的副本,因此不需要重新传输资源。

4xx 客户端错误

这类的状态码代表了客户端看起来可能发生了错误,妨碍了服务器的处理。

  • 400 Bad Request 是明显的客户端错误(例如,请求格式错误,size 太大,无效的请求消息或欺骗性路由请求)。
  • 401 Unauthorized 表示需要客户端验证。与 403 不同的是,对于 401,客户端可以重复提交一个包含恰当的 Authorization 头信息的请求。在测试的时候,我们可以使用 http://username:password@domain.com/ 来提交验证信息。
  • 403 Forbidden 表示服务器已经理解请求,但是拒绝执行它。与 401 响应不同的是,身份验证并不能提供任何帮助,而且这个请求也不应该被重复提交。当然服务器也可以返回一个 404 响应,假如它不希望让客户端获得任何信息。
  • 404 Not Found 就是请求失败。需要注意的是,当服务器不想揭示为什么请求被拒绝、或者没有其他适合的响应可用的情况下,也可能返回 404
  • 405 Method Not Allowed 对于一个只支持 POST 方法的 URI,如果使用 GET PUT 等方法访问它,就可以返回一个 405

5xx 服务器错误

  • 500 Internal Server Error:我也不知道出了什么错,是服务器错误的通用错误消息
  • 502 Bad Gateway:作为网关或者代理工作的服务器尝试执行请求时,从上游服务器接收到无效的响应。如 Nginx 将 example.com 反向代理到了 localhost:8080,而 8080 端口并没有软件运行,此时访问 example.com 就会收到 502
  • 504 Gateway Timeout:作为网关或者代理工作的服务器,未能及时从上游服务器(URI 标识出的服务器,例如 HTTP、FTP、LDAP)或者辅助服务器(例如DNS)收到响应。注意:某些代理服务器(如 V2Ray)在DNS查询超时时会返回 400 或者 500 错误。

如何选择最合适的状态码

这是一个非常宏大的问题,只能说具体情形具体分析。

一个方法是参考现有的代码或后端框架等等,如 Django REST Framework 提供的通用模板中,对象创建成功用 201 Created;登录成功返回 200 OK 以及登录信息;删除成功返回 204 No Content

还有一个方法就是在 Stack Overflow 上搜索你的行为 + REST APIhttp status code,会出现大量的结果供参考,如 logout http status code 会搜到关于注销应当返回什么,返回的状态码是否有意义这类问题。

REST API

了解了 HTTP Status Code 后,另一个问题就是 REST API 了。