RESTful API接口设计规范与最佳实践
当前位置:点晴教程→知识管理交流
→『 技术文档交流 』
Part1介绍RESTFull 接口设计目前广泛应用于各种软件系统中,特别是前后端分离架构的web应用。相信各位web应用的开发者对这个概念并不陌生,但是我们经常会遇到几个这样的疑惑或者问题:
在我们试图搞清楚以上几个问题之前,首先需要读者了解或者阅读过关于RESTfull的定义,这类定义百度一搜一大把这里就不重复赘述了。接着是最好你实践过这类风格设计的接口,如果你心中也同样有这几个问题或者疑问那就更好了,当然最后这两点要求并不是必须。 如果你已经阅读过关于RESTfull的相关定义,你就会发现RESTfull是一种接口设计风格,它制定了一些原则条件,只要你遵守了,就算是RESTful风格的接口设计。 那么问题就来了,这里面就存在很多灵活空间了,比如说我部分遵守,部分不遵守,可以吗?可以。或者说我在遵守的基础上,再自定义一些行为,可以吗?可以。 各种诸如此类的实践路线导致了我们很难在开发生涯中真的看到有两个或更多的接口实现了一模一样的RESTfull风格接口,即便他们的业务是一样的。这是因为RESTfull本身既然是一种设计风格,那么风格发挥的主动权自然就是在开发者身上,而且绝大多数的项目所开发的API接口都是对内或者有限对外开放的,所以对于RESTfull的实践是否合格更多取决于内部团队老大的看法。
这里我个人觉得有一部分原因是同行衬托,RESTfull基于HTTP协议,采用json格式的字符串作为传输内容,相对于过去的SOAP协议,采用XML格式标记语言来说,RESTfull无论从开发成本或者网络传输来说都显得轻量太多太多。而前面提到的,关于实际开发出来的RESTfull接口风格迥异的问题实际上并没有太糟糕,为什么这么说呢?因为最起码的一点是无论实际设计出来的接口再奇葩,总归是基于HTTP协议和使用JSON字符串来传递数据,这最起码保证了我们在调用别人设计好的接口的时候足够简单。 当然,能调用跟实际交互还有一段很长的距离,而中间这个过程你是否舒适,有一部分就体现在接口细节设计上了。按照一般的经验,像这种”标准化“的设计,我们会封装一些基础方法来实现接口的调用和数据接收,但现实却是无法实现的。因为RESfull接口的具体实现细节上是因人而异的,这就导致了我们封装的调用或者解析代码未必能够完全复用,很典型的例子就是我们一开始抛出来的那几个问题。 这时候读者们肯定想说,还是想吐槽,是的,我们可以吐槽一个接口设计得很糟心,让我们调用起来很难受,但是我们又不可否认他确实遵守了RESTfull的基本规定,你可以发送一个HTTP请求,通过JSON来提交和接收数据,你完全拿对方没办法。所以这也就是为什么我们一开始给出的答案是:没有对错。我们可以吐槽一个接口设计得非常糟糕,但是不能说这个接口不是RESTfull接口,但是,我们可以评判一个接口是否严格遵循了RESTfull风格设计以及遵循的程度有多高。 我们可以从开局的几个问题入手来尝试评判下相应的接口设计是否很好的遵循了RESTfull风格设计。 Part2为什么接口只设计了GET和POST两种请求方法类型?
从上面的表格可以看出,不同类型的请求方法有着自己明确的含义,在理想的情况下,我们可以通过一个请求类型+请求地址的形式,直观的看出一个接口的作用,比如:
这里读者可以尝试做一个阅读理解。 那么这里问题就来了,既然HTTP的请求方法类型有助于我们理解一个接口的作用,为什么在有些接口中唯独只会使用GET和POST呢?这里面我觉得原因有很多,有些可能我也想不到也猜不到,但是我从个人开发经验上尝试猜测一下。
坦白说,除了查询请求这种无可争议的使用GET之外,其他的全部归为POST无疑是一件很方便的事。你不需要花时间去考虑接口的行为然后决定要定义成什么请求方法类型,反正具体的实现逻辑都是一样的,而且POST方法的描述也似乎能涵盖到其他几个类型的请求方法。但这里读者可能会说,在某些场景下会有歧义,比如说我们要调用一个接口实现删除一个用户:
这里我们复用了前面其中一道阅读理解题并把类型改成了POST。这里第一眼看上去确实不能很好的表达接口的意图,但是我们有接口文档呀,我在相应的接口名称中写清楚再放大字体说这个接口是删除用户用的不就完事了?这么一听好像也有道理。所以综合看来,细分各个方法请求类型似乎变成一件很多余的事,吃力不讨好,干脆就GET/POST一把梭了。 说到这里,我们再回过头来看看问题本身,做错了吗?没有。那严格遵循了RESTfull风格设计了吗,那倒是并没有。
遵循 RESTfull
不遵循RESTfull
从这里的示例可以看出,在不遵循RESTfull风格设计的情况下我们难免需要在接口URL地址中增加一些描述性的单词,这会导致路由接口地址变得很冗长和不够优雅,当然如果你觉得这不是什么问题那也是没错的,对,你没错。
Part3为什么接口是否请求成功,HTTP状态码永远只会是200?
从上面表格可以看出,HTTP码是用于标识本次请求响应的结果状态,通过HTTP状态我们可以直观的判断出本请求是不是成功的,但是为什么有些接口设计的情况是无论成功与否都只会返回200的状态码呢?
首先假设我们把所有请求响应的HTTP状态码都标识为200,那么我们必然需要在响应内容中增加一些字段来描述本次错误,例如:
这里大家可能会觉得,我们已经有code和message字段来描述本次请求的错误了,完全不需要HTTP状态码。这里乍一看是没有问题的,前端也能在统一异常处理的层面很好的捕获异常。 但是,当你的系统到了一定的规模(这个很容易达到,并不要求需要多大的规模体量,只要不是demo项目),你的错误类型就会有很多种,往往我们的错误码清单会很长,当然这对于后端开发来说不是啥问题,因为这个信息其实是给前端开发者处理的,但是前端开发者在处理这些错误的时候就难受了。 难受在哪?假设我们现在有10个关于账户异常的错误码,10个关于业务A的错误码,10个关于业务B的错误码,一共30个。这里面有个业务需求,就是某些特定的错误码需要前端做出特定的行为,比如说跳转到指定页面,或者强制退出啥等等。那么这时候前端在统一异常处理的时候咋做?那就是各种 看起来似乎也问题不大嘛,是的,接着我们需求变了,和原来不一样了,原来的分支判断条件可能不适用了,错误码改了,含义不一样了,或者又增加了30个新的错误码,那么这时候前端开发者就炸了。
比如说给后端传递了错误的参数,这种一般后端在校验不通过的时候,会返回的HTTP状态码是400。这类提示信息是需要把具体错误信息展示给用户作为警告提示的,那么前端开发者在统一异常处理的时候,只需要判断HTTP状态码是不是400,是的话直接把具体内容以各种弹出提示的形式展示即可,不用关心具体的错误码又是什么(需要特殊处理的除外)。还有一种是401和**403 **HTTP状态码的错误,这两种都是跟权限有关的错误,前端开发者在做统一异常处理的时候也可以进行针对性的统一捕获处理。
相对于单纯依靠错误码,HTTP状态码+错误码的方式让前端开发者更容易实现封装和统一处理,前端开发者根据HTTP状态码定义不同的响应处理,可以大大减少开发工程量和降低沟通成本。但是这里读者们可能会说,我们可以把错误码按范围划分,实现比如1~99是代表XX类型错误,100~199是XX类型错误。这个确实可以,但是这等于是换了条路开倒车,其实还是会有一开始的提到的痛点问题出现。而且错误码因为是团队定义的,如果维护不善会导致各种前后端开发者信息不同步的问题,既然通过HTTP状态码的定义就能解决大部分问题了为什么不用呢? 最后总结一下这个问题就是,强烈建议严格按照HTTP状态码的定义区分接口响应的HTTP状态码,错误码作为一种细分的补充。 Part4HTTP状态码不存在,返回 200 还是 404 ?问题: 当一个查询的结果为空的时候,为什么有的接口设计会返回异常(HTTP状态码404或其他),有的则是会返回请求成功(HTTPS状态码200),但是返回结果是空数组或者null等表示结果为空的标识? 解析:这个问题情况有点特殊,理论上来说,当我们查询了资源然后结果是不存在的时候,这个时候用404的HTTP状态码来标识本次请求的响应状态是一点问题都没有的,也是非常规范的做法。但是这是建立在业务场景规定,查询结果为空的时候属于异常的前提上。 1返回HTTP状态码 |
关键字查询
相关文章
正在查询... |