MDN Web Docs (opens new window) 维基百科 (opens new window)
# 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
请求的用户的当前页面,应当选用 201
或 202
。
以及 206 Partial Content
表示报文包含的是请求的内容的一部分,这一般用于上传/下载的文件相当大的时候(下载的时候抓一下包就能看到很多的 206
)。
# 3xx 客户端需要进一步操作
通常来说,“进一步操作”就是指的重定向,因此最常用的也就是 301
302
307
308
这四个。
即 301 Moved Permanently
、302 Found
(或 302 Moved Temporarily
)、307 Temporary Redirect
、308 Permanent Redirect
。
Stack Overflow (opens new window) 上有一个表格非常形象:
永久重定向 Permanently | 暂时重定向 Temporarily | |
---|---|---|
允许将 POST 方法改为 GET | 301 Moved Permanently | 302 Moved Temporarily |
不允许将 POST 方法改为 GET | 308 Permanent Redirect | 307 Temporary Redirect |
何谓 Permanently
和 Temporarily
?
- 字面上理解:
Permanently
指的是用户访问的网站永久迁移到新网址了,而Temporarily
指的是用户访问的网站暂时(可能是 24-48 小时内)迁移到新网址; - 对于浏览器:
- 对于
Permanently
的结果,浏览器会缓存original_url
和redirect_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 API
或 http status code
,会出现大量的结果供参考,如 logout http status code
会搜到关于注销应当返回什么,返回的状态码是否有意义这类问题。
# REST API
了解了 HTTP Status Code 后,另一个问题就是 REST API 了。