使用标准的状态码
在与REST服务进行交互的时候,用户需要通过服务所返回的信息决定其所发送的请求是否被适当地处理。这部分功能是由REST服务实现时所使用的协议所决定的,与REST架构无关。而在基于HTTP的REST服务中,该功能就由HTTP响应的状态码(Status Code)来完成。因此在设计一个REST服务时,我们需要额外地注意是否返回了正确的状态码。
但是这些预定义的HTTP状态码并不能满足所有的情况。有时候一个REST服务所希望返回的错误信息能够更加精确地描述问题,例如在用户重设密码时,我们需要在用户所输入原密码与系统中所记录的密码不匹配时返回“您所输入的密码有误”这样的消息。在HTTP协议中,我们并没有办法找到一个能够精确地表示该意义的状态码。
因此在通常情况下,REST服务都会在响应中额外地提供一个说明性的负载来告知用户到底产生了什么问题。例如对于上面的重设密码失败的情况,服务端可能会返回如下响应:
1 HTTP/1.1 400 Bad Request
2 Content-Type: application/json
3 Content-Length: xxx
4
5 {
6 "error_id" : "100045",
7 "header" : "Reset password failed",
8 "description" : "The original password is not correct"
9 }
上面的示例响应中主要包含以下的说明性信息:
- 服务端响应的状态码。页面逻辑可以通过判断该状态码是否是4XX或5XX来判断是否请求出错,从而在页面中展示一个警告对话框。
- 服务所提供的内部错误ID。通常情况下,该内部错误ID也需要在警告对话框中展示出来。从而允许软件用户根据内部错误ID来获取支持服务。
- 错误的标题及简述。通过该错误的标题及简述,软件用户能够了解系统内部到底发生了什么,并在是用户输入错误的时候允许用户自行修改错误并重新发送正确的请求。
在该错误中,最关键的当属服务端的响应代码。一个响应代码不仅仅标示了请求是否成功,更有用户该如何操作的含义。例如对于401 Unauthorized响应代码而言,其表示该响应没有提供一个合法的身份凭证,因此需要用户首先执行登陆操作以得到一个合法的身份凭证,然后该资源可能就可以被访问了。而403 Forbidden响应代码则表示当前请求已经提供了一个合法的身份凭证,但是该身份凭证并没有访问该资源的权限,因此使用该身份凭证登陆重新登陆系统等操作并不能解决问题。
因此在返回错误信息之前,软件开发人员首先需要考虑清楚在响应中到底应该使用什么样的响应代码。而正确地选择响应代码则建立在软件开发人员对这些响应代码拥有一个正确的理解的前提下。
当然,要将所有的响应代码完全理解也需要大量的工作,而且REST服务的用户也可能并没有那么多的领域知识来了解所有的响应代码的含义。因此在很多基于HTTP的REST系统中,系统在标示错误时只使用一系列常用的响应代码,如400,401,403,404,405,500,503等。在用户请求被处理时,系统将返回200 OK,表示请求已经被处理。而在处理时发生错误时则尽量使用这些响应代码来表示。如果一个错误较为复杂,那么直接返回400或500,并在响应的负载中提供具体的错误信息。
不得不说的是,这种做法有时显得简单粗暴,尤其是对于一个开放平台而言则更是致命的。当一个第三方厂商为一个开放平台开发一个应用软件,却每次只能得到一个400错误,那么其内部应用逻辑将无法判断到底是哪里出了问题。为了能让用户知道这里产生了错误,该第三方软件只能将开放平台所给出的信息直接显示给用户。但是这些信息实际上是建立在开放平台这个语境下的,因此对于第三方厂商的用户而言,这些信息晦涩难懂,甚至可能一点帮助也没有。
也就是说,到底如何组织这些响应代码需要用户根据所编写的项目决定,尤其是该产品的使用者来决定。在定义一个平台时,尽量使用更多的HTTP响应代码,因为用户极有可能通过该平台编写自己的第三方软件。而在为一个普通的产品定义REST API时,将响应代码定得非常专业可能反而导致易用性的下降。
另外一点需要说明的是,个人不建议使用Wikipedia查找各个状态码的含义,而应该使用RFC所描述的各状态码的定义。 IANA提供了一张各个状态码所对应的RFC协议的列表,从而可以很容易地找到各个状态码所对应的RFC协议以及其所在的章节。该列表的地址为:http://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml
之所以不建议使用Wikipedia的原因主要有两点:
- 描述不够详细。在RFC定义中,每个状态码都对应着一段或多段文字,并且解释非常清晰。而在Wikipedia中,每个状态码常常只有一句话。
- 不够准确。在Wikipedia的Reference节中,我们可以看到一系列特定平台所定义的状态码,如Spring Framework所定义的420 Method Failure等。这非常具有误导性。