随着先后端分离愈来愈广泛, 后端接口规范也就愈来愈重要了. 一套良好的接口规范能够提高工做效率, 减小沟通障碍.html
一般咱们都会采用 REST 方式来提供接口, 使用 JSON 来传输数据.前端
名词 | 含义 |
---|---|
前端 | Web前端, APP端, 桌面端等一切属于用户界面的这一层 |
后端 | 即服务器端, 指一切属于用户界面之下的这一层 |
先后端接口 | 前端与后端进行数据交互的统称, 也叫作数据接口, 属于一种远程调用, 通常指前端经过HTTP(ajax)请求获取到的数据或者执行的某项操做. 为确保先后端(工程师)的协做沟通, 通常由前端和后端一块儿来定义接口的规范, 规范的内容通常包含接口的地址, 接口的输入参数和输出的数据格式(结构), 最终由后端来实现这些规范, 为前端提供符合规范的接口 |
[前端] -------- ^ | | 先后端接口 | | -------- [后端]
在开发以前必定要先定义好接口规范, 至于接口应该由前端来定仍是后端来定, 这个还得看公司的具体状况, 但必定要让先后端都确认无误, 特别是接口协商要点.java
以避免出现先后端分离以后最容易出现的扯皮现象. 特别是当你碰到作事不主动(无责任感)的后端, 什么都要前端来催. 好比什么接口又缺了一个字段没有提供啦, 什么又少了一个接口啦, 等等诸如此类. 后端不去熟悉业务, 也不看界面原型和需求, 只管把接口作完, 任务完成就万事大吉了, 天天除了等前端通知哪里要修改, 本身就像没事人同样.node
因此说定好接口, 先后端一块儿来确认好接口是多么的重要, 否则你就等着干着急吧. 固然了, 想一次性完美地将全部接口都定义出来, 有点不太现实, 须要调整的状况在所不免, 因此仍是但愿后端可以主动一点, 先后端沟通的时候就轻松得多, 你们的效率就都提升了.android
由前端(APP端)和后端一块儿协定接口规范的内容, 肯定每个接口的地址(URL), 输入(request)和输出(response), 必要的时候详细注释每个字段的含义和数据类型.git
具体须要定义哪些接口, 能够按照下面的思路来整理github
null
的对应数据类型初始值, 例如对象类型的返回空对象({}
), 数组类型的返回空数组([]
), 其余原始数据类型(string
/number
/boolean
...)也使用对应的默认值result.fieldName
result
为 null
, 可想而知会报错 Uncaught TypeError: Cannot read property 'fieldName' of null
"status": 1
http://a.res.com/path/to/img.png
这就是完整的, 前端直接使用这个 URL/path/to/img.png
这就是部分的, 通常省略域名部分, 前端须要本身拼接后才能使用 'http://a.res.com' + '/path/to/img.png'
1458885313711
, 或者参考 Date.prototype.toJSON 提供 ISO 标准格式(例如须要考虑时区时)2017年1月1日
JavaScript
会发生溢出, 形成获得的数值错误
{"id": 362909601374617692}
前端拿到的值倒是: 362909601374617660
全部的接口定义在项目前端静态文件目录的 _mockserver.json
文件中, 启动 puer-mock
服务, 便可使用这些接口得到符合规范的假数据, 也能够查看接口文档.web
具体 puer-mock
的详细使用手册和 _mockserver.json
如何配置接口请参考 puer-mock 项目, 或者参考项目中已经配置好的其余接口.ajax
因为接口规范的定义和接口的实际实现是分开的两个部分, 并且涉及到多人协做, 所以在开发过程当中可能出现接口规范与实现不一样步, 最终形成实际的接口不符合规范的定义, 接口规范就会慢慢失去存在的意义.json
为了尽可能避免这种问题, 后端在实现接口的过程当中应该确保与接口规范保持一致, 一旦出现分歧, 必须同步修改接口规范, 尽量保持沟通.
接口根路径 - Root Endpoint 推荐为: http://api.yourdomain.com
或者 http://yourdomain.com/api
接口地址即接口的 URL, 定义时使用相对路径(即不用带上域名信息), 建议分模块来定义, 推荐 REST 风格, 例如
GET /user/:id
表示获取用户信息POST /user
表示新增用户向接口传递参数时, 若是是少许参数能够做为 URL query string 追加到接口的 URL 中, 或者做为 Content-Type: application/x-www-form-urlencoded
放在请求体(body
)中(即表单提交的方式)
对于复杂的接口参数(例如嵌套了多层的数据结构), 推荐在 HTTP 请求体(body
)中包含一个 JSON 字符串做为接口的参数, 并设置 Content-Type: application/json; charset=utf-8
.
例如
查询 VIP 用户的接口
POST /users?limit=10 HTTP/1.1 Content-Type: application/json; charset=utf-8 { "name": "hanmeimei", "isVip": true }
返回的响应体类型推荐为 Content-Type: application/json; charset=utf-8
, 返回的数据包含在 HTTP 响应体中, 是一个 JSON Object. 该 Object 可能包含 3 个字段 data
, status
, statusInfo
HTTP/1.1 200 OK Content-Type: application/json; charset=utf-8 { "data": {}, "status": 0, "statusInfo": { "message": "给用户的提示信息", "detail": "用于排查错误的详细错误信息" } }
字段名 | 字段说明 |
---|---|
data | 业务数据 必须是任意 JSON 数据类型(number/string/boolean/object/array). 推荐始终返回一个 object (即再包一层)以便于扩展字段. 例如: 用户数据应该返回 {"user":{"name":"test"}} , 而不是直接为 {"name":"test"} |
status | 状态码 必须是 >= 0 的 JSON Number 整数.
|
statusInfo | 状态信息 必须是任意 JSON 数据类型. 推荐始终返回一个 object 包含 message 和 detail 字段
|
例如
接口处理成功时接口返回的数据
{ "data": "api result" "status": 0 }
接口处理失败时接口返回的数据
{ "status": 1, "statusInfo": { "message": "服务器正忙", "detail": { "exception": "java.util.List" } } }
这样咱们就能够很是容易地经过判断 status 来处理数据了
if (!response.status) { // status 为 0 或者没有 status 字段时表示接口成功返回了数据 console.log(response.data); } else { // 失败 console.error(response.status, response.statusInfo); // 统一由服务端返回给用户的提示信息 alert(response.statusInfo.message); }
status
字段该如何取值采用先后端分离开发模式的项目愈来愈多, 前端负责调用后端的接口来展示界面, 若是有界面显示异常, 须要有快速方便的手段来排查线上错误和定位出职责范围
综合了经验总结和行业实践, 最简单有效的手段是制定出一套统一的错误码规范, 协助多方人员来排查出接口的错误
例如
所以咱们肯定提示信息规范为: 当后端接口调用出错时, 接口提供一个用户能够理解的错误提示, 前端展现给用户错误提示和错误码, 给予用户反馈
对于错误码的规范, 参考行业实践, 大体有两种方案
A101
, B131
具体实践以下
错误码固定长度, 以区间来划分错误类型(例如 HTTP 的状态码)
例如: 10404 表示 HTTP 请求 404 错误, 20000 表示 API 调用失败, 30000 表明业务错误, 31000 表示业务A错误, 32000 表示业务B错误
错误码可不固定长度, 以首字母来划分错误类型, 可扩展性更好, 但实际运做仍是须要划分区间
例如: H404 表示 HTTP 请求 404 错误, A100 表示 API 调用失败, B100 表示业务A错误, B200 表示业务B错误
关于错误分类的原则, 咱们能够根据发送请求的最终状态来划分
错误码可不固定长度, 总体格式为: 字母+数字
, 字母
做为错误类型, 可扩展性更好, 数字
建议划分区间来细分错误
例如:
A
for API: API 调用失败(请求发送失败)的错误, 例如 A100
表示 URL 非法H
for HTTP, HTTP 异常状态的错误, 例如 H404
表示 HTTP 请求404错误B
for backend or business, 接口调用失败的错误, 例如 B100
业务A错误, B200
业务B错误C
for Client: 客户端错误, 例如 C100
表示解析 JSON 失败发送 HTTP 请求 ┌───────────┴───────────┐ 发送成功¹ 发送失败² │ │ ┌──────────┴──────────┐ A 例如: A100 得到 HTTP 响应 没法得到 HTTP 响应³ │ │ HTTP status A 例如: A200 ┌──────────┴──────────┐ HTTP 成功(200-300) HTTP 异常 │ | {data, status, statusInfo} H${HTTP status} 例如: H404 ┌───────────┴───────────┐ 接口调用成功(status:0) 接口调用失败 ┌────────┴────────┐ | 客户端处理出错 客户端处理正常 B${status}${statusInfo.message} 例如: B100 | C 例如: C100 - 发送成功¹: 服务端收到了 HTTP 请求并返回了 HTTP 响应 - 发送失败²: HTTP 请求没有发送出去(例如因为跨域被浏览器拦截不容许发送), 未到达服务端(即服务端没有收到这个 HTTP 请求) - 没法得到 HTTP 响应³: 服务端收到了请求并返回了响应, 但客户端因为某些缘由没法得到 HTTP 响应, 例如请求的超时处理机制
${错误码}
) ${HTTP 方法}
${HTTP URL}
${请求参数}
${请求选项}
${请求返回结果}
接口调用出错(H404) GET https://domain.com {foo: bar} {option1: 'test'} {status: 404}
规范实现: weapp-backend-api
GET /contact
获取联系人, POST /contact
新增/修改联系人362909601374617692
, 做为 JSON 数据返回给前端, 前端拿到的值变成了 362909601374617660
{"sex": 1, "sexText": "男"}
{"pic": "https://domain.com/a.png"}
{"createTime": 1543195480357, "createTimeText": "2018年11月26日"}
有范云协做 让项目的协做姿式更有范儿
- 交互阶段说明
- 交互设计师根据产品方的需求对产品进行行为设计和界面设计的阶段,主要产出物为交互设计稿
- 开发工程师须要作的事情是针对产品需求、交互设计稿中的内容进行技术评审,为产品方、交互设计师提供可行技术实现解决方案,对于多种不一样解决方案需针对各类解决方案作分析说明,务必准确传达各类方案的优缺点,并根据需求给出建议方案
- 系统设计说明
- 各端开发工程师针对产品需求说明、交互设计稿开始设计系统架构、拆分子系统、划分子系统模块、协调端与端之间的接口规范,这个阶段各端根据实际状况输出若干系统设计说明书等文档
- 除此以外更重要的是输出端与端之间通讯的接口规范,而这个规范则能够借助 NEI 平台 来完成
- 编码阶段说明
- 开发工程师根据系统设计阶段的输出,用代码来实现这样的系统,包括技术方案的选型、项目框架的搭建、工具及环境的配置等
- 其中有些工做能够借助于有范云协做提供的自动化工具 NEI-Toolkit 来完成,好比项目的初始结构代码、在 NEI平台 上定义好的接口规范等
- 自测阶段说明
- 各个端的工程师验证本身编写的代码的正确性,按角色不一样,测试方式也有全部不一样
- 对于前端和移动端工程师来讲,主要是须要测试各类可能的值会不会影响界面展现
- 对于服务端工程师来讲,主要是测试提供给客户端工程师使用的接口的正确性,对于不一样的输入参数是否返回了预期的结果
- 联调阶段说明
- 主要是连测试环境进行测试
- 对于前端和移动端工程师来讲,主要是须要将本地容器提供的接口换成测试环境的接口
- 测试阶段说明
- 开发工程师开发完成后提测的过程,是产品上线前的最后环节
- 测试工程师会对接 NEI 平台生成接口测试用例代码并集成到自动化测试平台运行,若是NEI平台的接口定义与实际提测的项目不符则这次提测失败,需由开发对照 NEI 平台检查接口实现状况,因此能够保证 NEI 平台上的接口定义始终与线上保持一致
参数名 说明 imei 国际移动设备身份码 imsi 客户端用户标识 t TIMESTAMP,请求的时间戳 appkey 由服务端颁发的appkey sign md5签名串。为了减轻非法恶意请求,每次来自APP的请求都须要对请求参数进行签名以实现安全认证 lng 手机上获取的经度 lat 手机上获取的纬度 ci 渠道标识,格式为:channelId@应用名平台客户端版本,例如:1001@nzaom_android_1.0,其中1001表示应用宝
JSend | JSON API | JSON Schema | JSON-RPC | JWT | OAuth
Type Description Required Keys Optional Keys success All went well, and (usually) some data was returned. status, data fail There was a problem with the data submitted, or some pre-condition of the API call wasn't satisfied status, data error An error occurred in processing the request, i.e. an exception was thrown status, message code, data
最佳实践:更好的设计你的 REST API | RESTful API 设计指南 | Best Practices for Designing a Pragmatic RESTful API | HTTP API Design Guide | The RESTful Cookbook | RESTful API 编写指南
Restlet Studio - Web IDE for API design | Swagger | ReDoc | RAML | API Blueprint