登录
首页大数据时代别吵了,RestAPI的状态码和错误处理最佳实践来了
别吵了,RestAPI的状态码和错误处理最佳实践来了
2021-03-10
收藏

来源:麦叔编程

作者:麦叔

代码评审会上,气氛有点紧张!

别吵了,RestAPI的状态码和错误处理最佳实践来了

罗老师正在看张三的代码,并指出了一个问题:

你这个API,在用户没登录的情况下,应该返回401,不应该返回200。要遵守HTTP协议的规范。

张三对此不以为然的说:

我们约定了都返回200的,具体的错误信息放在返回的JSON里。我又没有违法,不能为了规范而规范吧。

罗老师竟无言以对。他赶快去查看Facebook,谷歌等业界大亨的做法,可是他们的做法也不统一。到底要不要遵守HTTP Status Code呢?

听我细细道来,本文涵盖:

  • HTTP和Rest API的基本知识
  • Rest API使用HTTP Status Code的最佳实践
  • Rest API的错误处理最佳实践

HTT协议和Restful API

你很可能已经熟悉HTTP和Restful API。不管你是否熟悉,让我们用1分钟的时间来简单回顾一下:

HTTP协议定义了浏览器和网页服务器之间的交互过程。它的核心概念就2个:

  • Request - 浏览器要打开一个网页,给服务器发送一个Request,里面包含了网址,参数,及其他信息。
  • Response - 服务器返回一Response给浏览器,包括状态码,比如200表示成功,4xx和5xx都表示不同类型的失败,以及网页的具体内容。

有了标准的协议就好办了,任何人都可以开发浏览器出来,只要你写的软件都能遵守这个协议就行。我记得我研究生时候一门课的大作业就是开发一个简易的浏览器。

控制了浏览器,就控制了网络流量,就不怕没钱赚了,所以各大厂商都在努力推广自己的浏览器,就有了IE, Edge,Chrome,FireFox,QQ浏览器,以及360浏览器等。有的浏览器又好用又文明,有的浏览器很流氓,有的浏览器不遵守协议,让开发人员恨得牙根痒痒。

Rest API说白了就是一个网页地址,不过它只返回JSON或者XML格式的数据,而不是HTML网页。

HTTP Status Code

每个HTTP的Response都包含一个Status Code,表示请求的状态,是成功,还是失败,失败的原因是什么等等。

HTTP的Status Code一共有几十个,详细列表可以查看相关标准。但绝大部分人平时只会接触到最常见的少于10个的代码:

代码

含义

说明

200

请求成功


201

创建成功

专门用于创建新的记录的时候

301

永久重定向

网址永久变更成另外一个网址

302

临时重定向

网址临时变更成另外一个网址

400

无效的请求

请求的网址无效等

401

没有登录

需要登录才能访问

403

没有权限

虽然登陆了,但是没有权限

404

请求资源不存在

请求的东西不存在,比如某个人的信息

500

服务器端错误

服务器端发生了错误

有了这套标准,处理请求的程序首先根据状态码判定请求是否成功,然后做相应的处理。

Rest API是否应该遵循HTTP Status Code

Rest API理论上也应该遵守HTTP的规定,根据不同的情况,返回相应的状态码。但理论只是理论,大家对此的认识是不同的。基本上分成了两派:

  • 200派:不管对错,一律返回200,在返回的JSON中再具体指明错误的原因。
  • 正规派:另外一派坚持使用规范的HTTP状态码。如果是没有登录,就返回401,如果是没权限就返回403。

这两派都有重量级的公司参与,比如FaceBook就是200派,而Google, Twilio等是正规派:

别吵了,RestAPI的状态码和错误处理最佳实践来了

200派的理由很简单:反正我都需要处理返回的JSON,干脆我就把具体状态写在JSON里面,就不用管HTTP的状态码了,都用200好了。你看Facebook这样的大公司都用200了。

而正规派的人的理由就显得略微有点不正规,大部分人说:因为这是规范。Rest API是基于HTTP的,就应该遵守HTTP的状态码。

我是正规派的人,但我也觉得上面的理由有点薄弱。到底有什么好处?在什么情况下有好处?拿点实实在在的好处或者理由来?

首先,这肯定不是一个非黑即白的问题,200派和正规派都是可行的。只要API的提供者和请求者协调好,都不会带来很大的问题。但是我们仍然应该适度遵守HTTP的状态码。实实在在的理由如下:

  1. 作为一个开放的API,可能会被不同的消费者使用。为了最大限度的适应不同的消费者,最好的方法就是大家遵守一个业界规范,那就是HTTP的状态码。下面的2点都是举例来证明第1点。
  2. 很多JavaScript框架设计上就是基于HTTP协议的,根据不同的状态码做不同的处理,比如下面的JQuery的Ajax请求就可以根据HTTP的状态码执行不同的代码块:$.ajax({
    url: 
    'https://maishucode.com/page/2',
    type: 
    'GET',
    success: 
    function(data){
    alert(
    '成功返回'); //返回2xx,执行这个代码块
    }, error: 
    function(data) {
    alert(
    '出错啦!'); //返回4xx或者5xx,执行这个代码块
    }});
    如果API没有正确的使用HTTP状态码,上面的代码中需要手动解析JSON里面的状态码,再做分支的判断。
  3. 为了通用,很多中间系统根据状态码来分析系统的访问数据,比如ELK可以根据HTTP的状态码分析有多少成功的请求,多少失败的请求。如果都统一返回200,那么就没法分析出:有哪些未登录的访问,有哪些未授权的访问,有多少服务器端错误等。但是这里有利也有弊,有些流氓的中间系统会根据状态码劫持网页,比如有些浏览器和路由器就会劫持404网页,显示它自己的广告页。具体做法是:当路由器或者浏览器发现请求返回的是404,它们就会丢掉Response,而显示一个自己的广告网页。这种劫持是非常无耻的行为。404也是服务器返回给请求者的一个消息,网页仍然可能包含重要的内容。再说了,不管什么消息,中间人都不应该劫持。
别吵了,RestAPI的状态码和错误处理最佳实践来了
  • 总结一下,我支持使用合理的HTTP状态码的。原因上面已经说了。但是慎用404,因为可能会被众多流氓劫持。但是还有两点:
  • 不要滥用HTTP状态码,基本上就用我前面列举出来的那些就够了。
  • 使用HTTP状态码后,仍然需要使用和业务相关的状态码。这就是下面要说的。

Rest API的错误处理最佳实践

使用了HTTP状态码以后,让API符合了一定的标准,这很好。但HTTP状态码不能涵盖我们具体的业务场景,我们仍然需要定义和业务场景相对应的错误码。下面我推荐一个错误处理的返回格式,举例如下:

{ "status":403,
   "error": {     
      "code":'40041',      
      "message":"用户缺少访问特工名单权限",     
      "moreInfo":"https://maishucode.com/errors/40041", 
      "traceId":"9527"      }, 
   "data":{
  }
}

下面是对每个字段的解释:

  • status: HTTP状态码,不能为空,必须和HTTP header中的状态码一致。
  • code: 具体业务代码,可以为空。这里需要技术人员和业务人员一起定义一套错误代码规则。
  • message: 对错误信息的简单解释
  • moreInfo: 对错误信息的详细解释的网址。包含错误的详细解释,可能的原因,如何修正等。
  • traceId: 通过这个字段可以去日志文件中查找和本次操作相关的日志。
  • data: 存放具体的业务数据。

我要说的说完了!虽然这没有绝对的对错,但是符合良好的规范,提供充分的信息给调用用肯定是没错的。你觉得呢?在留言区留下你的意见吧!

数据分析咨询请扫描二维码

客服在线
立即咨询