自定义RESTful API服务规范

一、为什么需要定义API服务规范

在如今微服务大行其道,如果各个服务之间没有统一的接口暴露标准,交互方式杂乱无章,这无疑是很痛苦的。

也许作为服务提供方(后端)来说,只需要让调用方按照自己的规范来接入API 就好,但是如果我们提供的服务不规范,各种奇怪的请求方式或响应体,那么相信不会有多少人来使用我们的服务。

即使在你公司内部,不对外提供API服务,也应该有一套标准的接口调用处理规范。这样,不管是前端还是服务端来调用你,或者是你调用其它服务,我们都不会为如何请求服务或如何解析请求响应体而花费太多的精力。

二、什么是 RESTful API

REST 全称是 Representational State Transfer,中文意思是表现层状态转移。 它首次出现在 2000 年 Roy Fielding 的博士论文中,Roy Fielding 是 HTTP 规范的主要编写者之一。 他在论文中提到:"我这篇文章的写作目的,就是想在符合架构原理的前提下,理解和评估以网络为基础的应用软件的架构设计,得到一个功能强、性能好、适宜通信的架构。REST 指的是一组架构约束条件和原则"。 如果一个架构符合 REST 的约束条件和原则,我们就称它为 RESTful 架构。
REST 本身并没有创造新的技术、组件或服务,而隐藏在 RESTful 背后的理念就是使用Web 的现有特征和能力, 更好地使用现有 Web 标准中的一些准则和约束。虽然 REST 本身受 Web 技术的影响很深, 但是理论上 REST 架构风格并不是绑定在 HTTP 上,只不过目前HTTP 是唯一与 REST 相关的实例。 所以我们这里描述的 REST 也是通过 HTTP 实现的REST。

以上定义摘自: 菜鸟教程-RESTful 架构详解

再介绍一篇 Spring 官网对 REST 的讲解, 原文地址:https://spring.io/understanding/REST

当你弄清楚了什么是 REST 后,就不难知道什么是 RESTful API 了。 对的,所谓的RESTful API 其实就是编写符合 REST 约束条件和原则的 API 接口,它是一种设计风格,一种思想,更讲究的是对资源 URI 的良好设计,对已有 Web 标准更好的运用。这儿就不多对概念性问题进行介绍,相信如果你仔细阅读过上述给出的两个原文地址的话,那么关于概念性的东西相信你已经能够了然于心。 我们更多偏向的是在编程中如何设计出更符合RESTful 架构的程序,在实战中也反向的加深我们对概念的理解,不得不引用一句名言:“实践是检验真理的唯一标准”。

三、常用 HTTP 状态码

HTTP 状态码是目前实现 RESTful API 中的重要组成部分。 当你发起一个 HTTP 请求的时候,服务端会响应一个状态码来告诉你本次请求的结果,客户端可根据这个状态码来判断请求是否被正确处理,再做下一步的操作,如解析响应体或交互错误信息等。

在我初到目前所在公司所接触的项目中,大部分都不是以 HTTP 状态码来做第一轮验证,里面几乎所有的 HTTP 状态码值都是 200,然后根据响应体的自定义返回码值来判别请求是否被正确处理。这种方式摒弃了绝大部分 HTTP 状态码,把所有的请求响应状态都归于 200,而 200在 HTTP 状态码来说就认为是得到了请求者期望的结果,已经是正常状态了,但是该方式却不能判定状态正常,还需要继续验证响应体里的返回码来决定是否正确。这种方式不是说不行,只要你规范了你所有的API都使用这种方式,这是没什么问题的。只是说如果我们要构建符合RESTful风格的API就不能采用这种方式了。

下面是列举的我在项目中用到过的一些 HTTP 状态码,当然,在具体的使用中并不是用到的状态码越多越好,需要结合自己项目情况来选用适合自己的 HTTP 状态码。

HTTP 状态码 含义说明
200 - OK 请求已成功,请求所希望的响应头或数据体将随此响应返回。出现此状态码是表示正常状态
201 - Created 请求已经被实现,而且有一个新的资源已经依据请求的需要而建立,且其 URI已经随 Location 头信息返回。假如需要的资源无法及时建立的话,应当返回'202 Accepted'
202 - Accepted 服务器已接受请求,但尚未处理。正如它可能被拒绝一样,最终该请求可能会也可能不会被执行。在异步操作的场合下,没有比发送这个状态码更方便的做法了
204 - No Content 服务器成功处理了请求,但不需要返回任何实体内容,并且希望返回更新了的元信息。响应可能通过实体头部的形式,返回新的或更新后的元信息。如果存在这些头部信息,则应当与所请求的变量相呼应。
如果客户端是浏览器的话,那么用户浏览器应保留发送了该请求的页面,而不产生任何文档视图上的变化,即使按照规范新的或更新后的元信息应当被应用到用户浏览器活动视图中的文档。
由于 204 响应被禁止包含任何消息体,因此它始终以消息头后的第一个空行结尾
400 - Bad Request 1、语义有误,当前请求无法被服务器理解。除非进行修改,否则客户端不应该重复提交这个请求。

2、请求参数有误。
401 - Unauthorized 当 前 请 求需 要 用户 验 证。该 响 应 必须 包 含一 个 适用于 被 请 求资 源 的WWW-Authenticate 信息头用以询问用户信息。客户端可以重复提交一个包含恰当的 Authorization 头信息的请求。如果当前请求已经包含了 Authorization证书,那么 401 响应代表着服务器验证已经拒绝了那些证书。如果 401 响应包含了与前一个响应相同的身份验证询问,且浏览器已经至少尝试了一次验证,那么浏览器应当向用户展示响应中包含的实体信息,因为这个实体信息中可能包含了相关诊断信息
403 - Forbidden 服务器已经理解请求,但是拒绝执行它。与 401 响应不同的是,身份验证并不能提供任何帮助,而且这个请求也不应该被重复提交。如果这不是一个 HEAD请求,而且服务器希望能够讲清楚为何请求不能被执行,那么就应该在实体内描述拒绝的原因。当然服务器也可以返回一个 404 响应,假如它不希望让客户端获得任何信息
404 - Not Found 请求失败,请求所希望得到的资源未被在服务器上发现。没有信息能够告诉用户这个状况到底是暂时的还是永久的。假如服务器知道情况的话,应当使用410 状态码来告知旧资源因为某些内部的配置机制问题,已经永久的不可用,而且没有任何可以跳转的地址。404 这个状态码被广泛应用于当服务器不想揭示到底为何请求被拒绝或者没有其他适合的响应可用的情况下。出现这个错误的最有可能的原因是服务器端没有这个页面
405 - Method Not Allowed 请求行中指定的请求方法不能被用于请求相应的资源。该响应必须返回一个Allow 头信息用以表示出当前资源能够接受的请求方法的列表。
鉴于 PUT,DELETE 方法会对服务器上的资源进行写操作,因而绝大部分的网页服务器都不支持或者在默认配置下不允许上述请求方法,对于此类请求均会返回 405 错误
415 - Unsupported Media Type 对于当前请求的方法和所请求的资源,请求中提交的实体并不是服务器中所支持的格式,因此请求被拒绝
500 - Internal Server Error 服务器遇到了一个未曾预料的状况,导致了它无法完成对请求的处理。一般来说,这个问题都会在服务器端的源代码出现错误时出现
503 - Service Unavailable 由于临时的服务器维护或者过载,服务器当前无法处理请求。这个状况是临时的,并且将在一段时间以后恢复。如果能够预计延迟时间,那么响应中可以包含一个 Retry-After 头用以标明这个延迟时间。如果没有给出这个 Retry-After信息,那么客户端应当以处理 500 响应的方式处理它。
注意:503 状态码的存在并不意味着服务器在过载的时候必须使用它。某些服务器只不过是希望拒绝客户端的连接

更多 HTTP 状态码可参考百度百科: HTTP状态码

四、怎么定义RESTful API服务规范

显然,如果你选择了RESTful架构风格,那么从一开始,就应该为团队定义好RESTful API服务规范,如同一开始就应该定义好编码规范一样。如果你是仔细阅读下来,并且对第三节中菜鸟教程介绍中的 菜鸟教程-RESTful 架构详解 进行了理解,那么你心中应该有了定义RESTful API服务规范的方式。

值得注意的是,目前越来越多的开发者们以及企业喜欢使用JSON来作为数据的交互格式,这些也应该定义到我们的RESTful API服务规范中去。

还有我觉得更为重要也必须要细致化的就是对于差错的处理方式,对于不同的 非2xx HTTP状态码,可以定义一个code与msg组成JSON响应串,当然,code和 msg 会根据实际业务场景而自定义,如:

  • HTTP状态码为400,响应结果为 {"code":400, "msg":"操作失败"}
  • HTTP状态码为401,响应结果为 {"code":40101, "msg":"token参数不存在"}
  • HTTP状态码为401,响应结果为 {"code":40102, "msg": "token验证失败"}
  • HTTP状态码为500,响应结果为 {"code":500, "msg":"服务器异常"}
  • HTTP状态码为503,响应结果为 {"code":503, "msg":"服务器异常,请稍后再试"}

其中code值40101, 40102等都是根据不同业务场景而定义出来的,前端可以根据code值自定义msg显示层,也可以直接把msg内容作为显示层,这些也应该定义到我们的RESTful API服务规范中去。

五、Spring 中实现 RESTful API

实现一个简单的 RESTful API 对于 Spring 来说无疑是毫无难度的,因为在 Spring 家族中已经对 RESTful 进行了原生态的支持。当然,其它语言也有其对应的REST框架。

下面给出我在 GitHub 上基于 Spring Boot 编写的简单 RESTful API 示例项目, 地址:restful-api-demo 大家可以很快的了解利用 Spring 怎么来快速编写自己的具有 RESTful 风格的 API 服务。

结束语:本文的内容不多,更多希望的是读者去阅读第三段中引用的两篇原文。 在我们平时工作中,也一定要多注意规范问题,尽量采用已有标准,再在之上做自定义,减少日常工作中的沟通成本。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,390评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,821评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,632评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,170评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,033评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,098评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,511评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,204评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,479评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,572评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,341评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,213评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,576评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,893评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,171评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,486评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,676评论 2 335