Code状态码码是接口设计中的常见概念,本文主要讨论接口开发中Code码设计。从客户端和服务器端开发的角度,给出具体的工程实践建议和思考。前端
从笔者以前的一份接口文档定义开始提及,文档中定义的服务端接口输出格式以下node
返回数据由两部分构成,第一部分是对结果集的说明,第二部分是data节点ios
{ "code": 4302, "message": "no sign", "time": 1487832032, "data": [] }
第一部分,不管错误与否,都会有以下片断。nginx
code:信息代号git
message:信息描述github
time:接口返回时间web
第二部分是具体数据以下:编程
data节点json
咱们能够 看到code=4302,4302并非一个HTTP 协议状态码,而是一个业务状态码,是业务领域的含义,并不是咱们常见的HTTP 协议层面的响应状态码。axios
在REST 接口设计规范中,咱们一般都会被引导为这里的Code 应该是HTTP 协议状态码 200,404 或者501等。
实际上这是实践中的一种折中的方式,Code 会包含HTTP状态码和业务状态码
业界为何会有这种实践,与客户端的解析数据方式有很大关系,下文中会给出答案。
说到这里,咱们引出了两个概念,一个是业务状态码,一个是HTTP请求状态码。
两个概念很好理解
业务状态码是服务端给出的关于业务描述的码,用于客户端明确得知本次请求的资源的状态状况。上文例子中的4032被认为是一个缺乏签名sign的业务状态码。有业务状态码输出代表当次HTTP 请求是通的。
业务状态码是可变的,没有业界标准,是一种资源状态描述,与HTTP响应状态码也不存在对应关系。
以下文图片HTTP-200 显示,接口是通的 HTTP 状态响应返回 200,可是业务没有执行成功,code用1 表示。
HTTP/1.1 200 OK Server: nginx Date: Wed, 13 Nov 2019 01:27:03 GMT Content-Type: application/json; charset=UTF-8 Transfer-Encoding: chunked Connection: close X-Powered-By: PHP/5.6.15 Access-Control-Allow-Origin: * Access-Control-Allow-Methods: POST, PUT, GET, DELETE, OPTIONS Access-Control-Allow-Headers: token, app-key, content-type, etcp-base Access-Control-Max-Age: 86400 X-Frame-Options: SAMEORIGIN X-Content-Type-Options: nosniff { "code": 1, "message": "states is wrong", "data": [] }
HTTP请求状态码是HTTP协议的一部分,用于代表HTTP响应状态。
HTTP 状态码是HTTP 协议的工程实现,不符合协议规定的服务器端实现,咱们能够认为 服务器的HTTP 实现是错误的。
这里举一个简单的幂等性例子,咱们知道DELETE 方法是幂等的,若是以前已经删除过特定的资源,再次请求时也应该返回200的响应码,而不是404资源不存在的响应。
为何上文中着重介绍状态码的两种分类,由于在业界开发中,这两种码会交叉使用,都有具体的使用场景,语义上不该该被混淆。
这里抛出几个问题
如何用Code码代表这次访问是链接成功的如何用Code码代表这次访问达到了客户端预想的结果
客户端应该先接收HTTP状态码仍是业务状态码
先对本文中的客户端作一个简单定义,即调用服务器端接口的调用者,主要是前端WebView,安卓和iOS工程师,统称大前端。前端WebView的请求会涉及到跨域CORS
其实简单来讲,客户端工程师最关心两个问题:
第一,接口有没有通。
第二,接口有没有返回我想要的数据。
有经验的客户端工程师会关心接口若是不通,返回提示是否能够指导我排除错误,或者说跟踪到问题所在。接下来接口设计是否合理,是否有隐患,就看工程师职业水平和职业素养了。
客户端HTTP 请求的通用方法是采用排除法,什么是排除法,客户端在请求服务端的REST 接口时,会先在网络层面判断接口是否通,包括404或者200。客户端只关心自己有用的Code,其他都按异常处理。
网络层判断这个任务客户端会交给具体的HTTP 拦截器 (Intercept),以后才会接受当次接口的描述信息也就是data 和code,作业务前端处理。
axios 就是一个主要用于浏览器请求的HTTP 客户端,包含请求响应拦截器(Intercept request and response)
Promise based HTTP client for the browser and node.js
如下代码是两段响应拦截,分别是拦截HTTP 协议的401验证不经过和自定义业务代码的验证不经过。
axios.interceptors.response.use(function (res) { return res.data; }, function (res) { let response = res && res.response || {}; if (response.status == 401) { tool.showToast('登陆已过时,请从新登陆。'); tool.removeReUserInfo(); location.hash = "#/login"; } else { tool.showToast('请求数据失败,请稍后再试。'); } });
axios.interceptors.response.use(function (res) { Indicator.close(); //首先关闭全部的提示窗口 var data = res.data; if (data.code == 4034) { //签名不合法 tool.showToast('签名不合法。'); } else if (data.code == 4033) { //token失效 tool.showToast('登陆已过时,自动登陆中。'); tool.removeUserInfo(); location.hash = "#/login"; } else { return data; } }, function (err) { // alert(JSON.stringify(err)); Indicator.close(); //首先关闭全部的提示窗口 tool.showToast('请求数据失败,请稍后再试。'); });
okhttp 是一个安卓平台的HTTP 客户端,其中包含一个网络拦截器(Network Interceptors)。网络状态码和业务状态码的截取都交给拦截器处理处理。
这里咱们从新梳理以前提出的三个问题,给出一些解决思路,同时总结一些经验
如何用Code码代表这次访问是链接成功的?
这里应该以HTTP 状态码为依据,主要有200, 401 ,代表请求是【触碰到关于的数据处理的业务部分了】如
HTTP/1.1 200 OK { "code": 0, "message": "客户端已经是最新版本", "data": { "code": 10 }, "debug_stack": [] }
HTTP/1.1 401 Unauthorized Server: nginx { "name": "Unauthorized", "message": "Token is expired", "code": 401, "status": 401, "type": "yii\\web\\HttpException" }
如何用Code码代表这次访问达到了客户端预想的结果?
这里以业务状态码的数据为依据,获取到的就是真实的。Code能够用 0 表示。
{ "code": 0, "message": "客户端已经是最新版本", "data": { "code": 10 }, "debug_stack": [] }
客户端应该先接收HTTP 状态码仍是业务状态码?
固然是先接收HTTP 状态码,其次是业务状态码,不混淆,也不能混淆。从软件分层的角度来讲,接收HTTP 状态码在接收业务状态码的上层,一般由拦截器来作,好比token过时的401阻挡。
通常状况下,0表示成功,1表示业务操做失败。业务复杂时,须要维护多种业务状态码。下图是微信平台的业务状态码枚举,场景较多。
接口字段整齐
这里所说的字段整齐是指服务提供方给到的数据结构是完整的,最通用的,如今大部分接口格式以下
三个字段应该都存在,能够为空,避免NULL。
{ "code": 200, "data": null, "message": "成功" }
对于提供接口开发的服务者而言,code和message字段都会给出,存在异议的字段是data。更严谨的说法是 请求的资源描述中伙包含资源状态编码和描述信息,如message。
当data 没有数据时,有的工程师喜欢把data置为null,或者直接不返回data字段。这两种方式都不合理,都会增长调用方的判断成本,尤为是null,若是调用方写法不严谨的话,很容易引起程序异常。
接口总会有返回值,data字段就是实际的返回值,能够是空字符串,空数组,bool类型。
图灵奖得主Tony Hoare 曾经公开表达过null是一个糟糕的设计,null老是表明着不肯定性。
业务状态码和异常是两个概念,切忌混淆。业务状态码指正常的业务处理结果的显示说明,而异常一般因为语法错误,数据缺失形成程序不能正常执行完成。不能经过业务状态码而屏蔽异常。
本文从接口文档开始,引出了状态码的概念,细分为网络状态码和业务状态码。结合服务器端和客户端的编程角度,介绍了各自的使用场景。在分布式服务化的网络架构中,清晰的网络状态码和业务状态码有助于服务链路的跟踪和服务的链路跟踪,尤为是异常的定位和捕获。业务状态码应该趋于同一化,与网络状态码相互补充。
参考文档中给出一些资源,有兴趣的读者能够参考阅读。