俗话说无规矩不成方圆,一个接口一种数据响应格式,一个开发人员一种开发格式,导致代码不规范,数据解析复杂化,维护更是难上加难。
一、接口响应数据格式,做到不使用的属性不返回
1、基础响应格式【其他格式在此格式上进行扩展】
{
"code":200,
"msg":"ok",
}
2、对象格式---以个人信息为例
{
"code":200,
"msg":"ok",
"data":{
"id":100,
"name":"poppy",
"age":20,
"sex":1
}
}
3、数组格式---通常为列表
{
"code":200,
"msg":"ok",
"data":[{
"id":1,
"name":"poppy",
"age":20
},{
"id":2,
"name":"thorn",
"age":18
}]
}
4、分页列表格式
{
"code":200,
"msg":"ok",
"data":{
"nowPage":1,
"totalPage":10,
"list":[
{
"id":1,
"name":"poppy",
"age":20
},
{
"id":2,
"name":"thorn",
"age":18
}
]
}
}
5、接口响应数据格式中,图片地址必须给出完整的地址
{
"code":200,
"msg":"ok",
"data":[
"http://xxx/file/upliad/20172514.jpg",
"http://xxx/file/upliad/20172515.jpg"
]
}
二、接口协商要点
1、接口必须返回统一的数据结构, 参考【接口响应数据格式结构】
2、接口查询不到数据时, 即空数据的情况下返回给前端怎样的数据
- 建议返回非 null 的对应数据类型初始值, 例如对象类型的返回空对象({}), 数组类型的返回空数组([]), 其他原始数据类型(string/number/boolean...)也使用对应的默认值
- 这样可以减少前端很多琐碎的非空判断, 直接使用接口中的数据
3、返回数据中图片 URL 需要完整路径
4、返回数据中页面跳转的 URL 是给完整的还是部分的
- 内部页面返回部分的, 或者只给ID, 由前端自己拼接, 例如只给出商品ID, 让前端自己拼接商品详情页的 URL
- 外部页面返回完整的, 例如广告位要跳转去谷歌
5、返回数据中日期的格式
- 对于需要前端再次处理的日期值(例如根据日期计算倒计时), 可以使用时间戳, 例如: 1458885313711
- 对于纯展示用的日期值, 推荐返回为格式化好的文字, 例如: 2017年1月1日
6、对于大数字(例如 Java 的 long 类型), 返回给前端时需要设置为字符串类型, 否则 JavaScript 会发生溢出, 造成得到的数值错误
- 例如: 返回 JSON 数据 {"id": 362909601374617692} 前端拿到的值却是: 362909601374617660
7、缩小单位保存数据,如:钱以分为单位、距离以米为单位。
7、聚合型接口,页面级API一个页面涉及到太多接口, 如果是一个个地调用, 会需要很多次请求, 有可以影响到前端的性能和用户感知(特别是首屏的体验), 因此可能需要将这些接口的数据合并到一起, 作成一个聚合型接口提供给前端来使用
8、一致性原则
- 1、前端需要哪些字段,API接口应该返回哪些字段,字段不多也不少。
- 2、更新功能尽量做到:初次返回的原始数据参数与提交更新的数据参数结构一致。
- 3、时间参数,尽量以一致格式的字符串传递, 如:
‘2019-01’ | ‘2019/01’
‘2019-01-01’ | ‘2019/01/01’
‘2019-01-01 12:12:12’ | ‘2019/01/01 12:12:12’
- 4、其它参数【待更新】
参考:https://github.com/f2e-journey/treasure/blob/master/api.md
三、前后端约定
后端
- 后端需要保证JSON格式的合法性,前端不对格式的合法性做判断
- 金额格式:所有金额以元为单位,显示性的后台返回的是格式化之后的,例如:6,800
- 时间格式: 尽量以一致格式的字符串传递 2019-01-01 12:12:12
- 数据接口中定义的key集合是后端返回的子集,即key不缺失(参考数据格式,允许传递更多数据)
- key使用驼峰命名,首字母小写
- 空对象请使用[]
- 空列表请使用[]
- 空字符串请使用''
- 默认数字请使用0
- 尽量避免使用null undefined
- 响应头Content-Type为"application/json; charset=UTF-8"
- 接口应该携带requestId唯一标示用来追踪问题
- 敏感度高的数据,客户端和服务器通过约定的算法,对传递的参数值进行签名匹配,防止参数在请求过程中* 被抓取篡改。
- 包含用户隐私的字段数据,需要加*号。如:手机号,身份证,用户邮箱,支付账号,邮寄地址等。
- "phone":"150****0000",
- "idCard":"3500**********0555",
- "email":"40*****00@qq.com"
-
优惠券用到分类及单位的须返回字段 不同内容返回不同的数据 按需返回
前端
- 请求头 application/x-www-form-urlencoded
- 请求字段使用驼峰命名,首字母小写
- 一个页面尽量只有一个拉取接口,减少类似这种的连续请求。
- 当请求需要缓存并且有需要及时更新的情况,可以分多个请求。
参考:https://www.sohu.com/a/339695913_120104204
四、状态码定义规范
状态码 | 说明 |
---|---|
200 | 查询成功 |
201 | 查询成功无记录 |
202 | 查询失败 |
1000 | 账户不存在或被禁用 |
1001 | 请求的接口不存在 |
1002 | 没有改接口的访问权限 |
1004 | 参数为空或格式错误 |
1005 | 数据签名错误 |
1010 | 余额不够,无法进行查询 |
1011 | 查询权限一杯限制 |
1099 | 非法IP请求 |
400 | 系统异常 |
500 | 服务器错误 |
... | ... |
四、接口协作
由于接口规范的定义和接口的实际实现是分开的两个部分, 而且涉及到多人协作, 因此在开发过程中可能出现接口规范与实现不同步, 最终造成实际的接口不符合规范的定义, 接口规范就会慢慢失去存在的意义.
为了尽量避免这种问题, 后端在实现接口的过程中应该确保与接口规范保持一致, 一旦出现分歧, 必须同步修改接口规范, 尽可能保持沟通.
请求方式
GET(SELECT): 从服务器取出资源(一项或多项)。
POST(CREATE): 在服务器新建一个资源。
PUT(UPDATE): 在服务器更新资源(客户端提供改变后的完整资源)。
DELETE(DELETE): 从服务器删除资源。
域名
专门的api应用使用独立域名 https://api.example.com
简单的可使用api前缀区分 https://www.example.com/api
版本控制
接口版本的控制,可以在程序发布时,不同版本的业务逻辑在一定程度上避免受到影响。
https://api.example.com/v{n}
应该将API的版本号放入URL。
采用多版本并存,增量发布的方式。
n代表版本号,分为整型和浮点型
整型: 大功能版本, 如v1、v2、v3 ...
浮点型: 补充功能版本, 如v1.1、v1.2、v2.1、v2.2 ...
瘦客户端
客户端任何的修改都是需要发版的,发版需要审核流程。
客户端尽量只负责展示逻辑,不处理业务逻辑
客户端不处理金额的计算
客户端少处理请求参数的校验与约束提示
拓展性
图片文案等,与校验规则类似,通过接口返回,并提供默认。
安全性
url连接一般采用https协议进行数据传输,可以提高数据交互过程中的安全性。
兼容性
区分版本
性能优化
合并接口
字段简写
无用字段清理
图片裁剪
局部刷新
预加载
其他
接口安全,防参数篡改
频率的控制
数据存储
是否需要依赖于第三方
服务降级,熔断和限流
拆分
扩展性
适配性
幂等
重复提交
部署
缓存穿透、缓存雪崩和缓存击穿
是否需要白名单
预加载
重试
异步
服务端推送或者客户端拉取数据
隔离(例如内网的中台服务,后端服务)
健康检查,后台大盘监控可视化,故障主动通知