张遂程 2018年02月06日16:15:03
没有最优的方案,只有最适合的方案,本文指出对APP接口设计的一些规范与大家分享和共勉,涉及到APP接口设计规范v1.0,设计案例的分享,和一些PHP编码的要求,目的在于开发出性能优异,结构清晰,维护便捷,安全,和高拓展性的接口。如果有说得不正确的地方,也请大家指出。
在项目中,要做到融会贯通,首先就应该做到多学习,学习大厂的经验和总结,如果能避免到别家遇到的坑,那么就最好了,如果避免不到,那么也能做到心中运筹帷幄。程序开发中有句很流行话就是,”不要重复造轮子”,要”时刻明确自己是搬砖民工,不是烧砖的窑”。
{
"users": [
{
"id": 1404376560,
"screen_name": "zaku",
"name": "zaku",
"province": "11",
"city": "5",
"location": "北京 朝阳区",
"description": "人生五十年,乃如梦如幻;有生斯有死,壮士复何憾。",
"url": "http://blog.sina.com.cn/zaku",
"profile_image_url": "http://tp1.sinaimg.cn/1404376560/50/0/1",
"domain": "zaku",
"gender": "m",
"followers_count": 1204,
"friends_count": 447,
"statuses_count": 2908,
"favourites_count": 0,
"created_at": "Fri Aug 28 00:00:00 +0800 2009",
"following": false,
"allow_all_act_msg": false,
"remark": "",
"geo_enabled": true,
"verified": false,
"status": {
"created_at": "Tue May 24 18:04:53 +0800 2011",
"id": 11142488790,
"text": "我的相机到了。",
"source": "" rel="nofollow">新浪微博",
"favorited": false,
"truncated": false,
"in_reply_to_status_id": "",
"in_reply_to_user_id": "",
"in_reply_to_screen_name": "",
"geo": null,
"mid": "5610221544300749636",
"annotations": [],
"reposts_count": 5,
"comments_count": 8
},
"allow_all_comment": true,
"avatar_large": "http://tp1.sinaimg.cn/1404376560/180/0/1",
"verified_reason": "",
"follow_me": false,
"online_status": 0,
"bi_followers_count": 215
},
...
],
"next_cursor": 5,
"previous_cursor": 0,
"total_number": 668
}
{
"request" : "/statuses/home_timeline.json",
"error_code" : "20502",
"error" : "Need you follow uid."
}
{
"user_buyer_get_response":{
"user":{
"nick":"hz0799",
"sex":"m",
"avatar":"http://assets.taobaocdn.com/app/sns/img/default/avatar-120.png",
"open_uid":"324324324"
}
}
}
{
"error_response":{
"sub_msg":"非法参数",
"code":50,
"sub_code":"isv.invalid-parameter",
"msg":"Remote service error"
}
}
除了上文说的响应方式外,还有一种API响应方式也是比较流行,代表者是百度,高德,支付宝等。
- 百度举例
{
address: "CN|北京|北京|None|CHINANET|1|None", #详细地址信息
content: #结构信息
{
address: "北京市", #简要地址信息
address_detail: #结构化地址信息
{
city: "北京市", #城市
city_code: 131, #百度城市代码
district: "", #区县
province: "北京市", #省份
street: "", #街道
street_number: "" #门牌号
},
point: #当前城市中心点
{
x: "116.39564504", #当前城市中心点经度
y: "39.92998578" #当前城市中心点纬度
}
},
status: 0 #结果状态返回码
}
{
"alipay_trade_precreate_response": {
"code": "10000",
"msg": "Success",
"out_trade_no": "6823789339978248",
"qr_code": "https://qr.alipay.com/bavh4wjlxf12tper3a"
},
"sign": "ERITJKEIJKJHKKKKKKKHJEREEEEEEEEEEE"
}
选型我们自己使用的API相应规则如下
正常响应示例
{
"status": 1,//状态值是1
"error_code": 0,//同时错误代码是0表示无错误
"message": "获取成功",//提示操作成功信息
"data": []//主体返回内容
}
错误响应示例
{
"status": 0,
"error": 20102,//2:业务级错误(1代码系统级错误)固定一个字符;01:指的是01这个业务比如保洁 固定两个字符;02具体错误信息固定两个字符,会整理成一个对照表格,前端需要翻译成友好的提示
"message": "用户id不能为空",//给前端程序员的不友好提示,指明错误的原因
"data": {}//data字段固定
}
这里概念的定义为与APP部分相互的部分,我们将从安全,版本兼容,命名规范,迭代,面向对象等多个方面说起
在app的后端设计中,一个很重要的因素是考虑通讯的安全性。
避免信息的泄露,最简单的方案是所有涉及到安全性的api请求,都必须要使用https协议。
因此,我们需要考虑的要点有:
APP对服务器端要求是比较严格的,在移动端有限的带宽条件下或者弱网络下,要求接口响应速度要快,,抛开后端的开发框架效率来说,对数据要求也比较严格,如果能做到app需要什么数据就传什么数据,不可多传,过多的数据量影响处理速度,最重要的是影响传输效率那么自然效率是最高的,但是这之间也要有个取舍,效率和接口设计思想之间,后面我们会提到面向对象的设计思想。
Restful风格:RESTfu设计原则,它被RoyFelding提出(在他的”基于网络的软件架构”论文中第五章)。而REST的核心原则是将你的API拆分为逻辑上的资源。这些资源通过http被操作(GET,POST,PUT,DELETE)。但现在看,一般的操作只有两种:GET ,POST。
{
"brand_name": "奥迪",
"car_model": "SUV",
"emission_standard": "国五",
"car_owner": {
"name ": "张三 ",
"driving_years": "5年",
"id": "666"
}
}
其中车主是一个对象,车子是一个对象,两者是既有关系又相对独立。
总结建议是,新设计的接口,需要考虑到多端不同展示,尽可能的偏向于面向对象,少量特殊处理可以面向页面。当然,后端代码上,都是以对象的形式存在,逻辑必须清楚。
其中一个原则,一看api名字就知道这个api是干啥。但是有个问题就是当你要负责几十甚至上百个api,你就知道不能”望名知api”是个什么样的痛苦。
就拿一个接口来举例吧
'/User/userRedDot/version/1'
这是我们在使用的一个接口,从接口名字来看,不难看出User这个是用户相关的一个功能,然后userRedDot小驼峰命名指的是用户小红点,然后接口的版本号是第一版。以上4部分构成了一个完整的接口命名。
接口文档中是会注明不同的接口该使用不同的传参方式
header参数部分:请求头部一般放入鉴权的相关参数,比如用户的token和签名,设备id,APP的标识,userAgent自定义等。
除去鉴权的参数,其他就是接口的入参传递(文档会注明传递方式):
1. 一维参数 按照POST/GET按照普通的form-data和urlencode方式即可
2. 多维参数 按照POST方式,并把body放入json的形式传递。
3. 新增数据 POST
4. 获取数据和修改数据用GET
系统级接口需要独立于业务之外使用,对于系统级接口,需遵循接口使用规则,对于非系统级接口,可由具体业务实现。但是安卓和ios需要统一。
打个比方,获取用户权限的接口,接口的使用规则由产品给出的,切换tab和从后台返回。
再比如,获取编辑用户爱好,婚姻情况,个性签名等筛选数据,按照接口使用规则,应该在进入用户中心点设置的时候请求,现在是在打开APP地方的进行请求,不符合接口使用规则。原因也在于以前没有给出接口使用规则。
特殊处理的接口需要在接口文档上注明使用规则,比如接口的先后顺序,接口的使用环境和频率。
对于接口返回,也需要安卓和ios进行同步处理,操作成功和 操作失败的信息提示,成功是都不处理还是都处理,失败的提示信息怎么处理,操作失败的时候提示信息需要明确。两个客户端不应该存在不同的处理方案。
接口不可能永远不变,它会随着需求的变化而做出相应的变动,这种变动也可以理解为兼容或者不兼容。大部分情况下直接在这个接口上叠加版本号,并兼容旧版本。App的新版本开发传参时则将传入新版本的version。
接口的变化一般会有几种:
1. 数据的变化,比如增加了旧版本不支持的数据类型(兼容:新增版本号,接口增量更新)
2. 参数的变化,比如新增了参数(兼容:新增版本号,接口增量更新)
3. 接口的废弃,不再使用该接口了(不兼容:原接口指定版本废弃,后端逻辑处理;原接口所有版本废弃,如果是业务流程修改,则停用原接口,并新开接口)
4. 如果整个接口系统的根基都发生变动的话,比如微博API,从OAuth1.0升级到OAuth2.0,整个API都进行了升级,就无法兼容,只能进行版本强制升级了。
有时候,一个接口的变动还会影响到其他接口,但做的时候不一定能发现。
服务端的程序在运行的时候,可能因为一个数据的转化或空指针异常什么的,都不能让程序奔溃,需要捕获异常并对异常进行处理,并返回明确的数据状态信息,不管是成功的,还是失败的,都必须要有数据返回给APP客户端,否则,接口的协议失去了所有的意义
app客户端的语言 java和object-c都是强类型语言,所以怎么处理空值显得特别重要,不合理的设计很容易造成app的闪退。
从后台的角度来说,api中返回的数据中,正确值和空值的类型必须一样,举例,用户名的字段是“realname”: “xxx”,如果用户名为空,则应该返回“realname”:”“。如果返回值是一个array,空数据则返回一个空array,如果返回值是一个对象,空数据则返回一个空对象,绝对禁止null值。
对于客户端,必须用个全局的函数来处理所有api的返回数据,需要有一个机制:对于某个客户端需要数据,如果api中缺失,客户端自动补上并给予默认值。
同时,在数据库设计的时候,一个合理的设计必须是所有字段都有默认值,不应该允许null值。null在大量的语言和数据库中,会带来无穷的问题。
如果服务端是php,还有一个问题,php中数组和字典都是array,但是可以用(object)[]返回对象,但在java和object-c中是不一样,这个问题一定要注意。
补充说明下json的六种数据类型数据类型和约定
前后端需要对数据类型进行约定:
- 时间日期型数据:直接返回格式化后的时间字符串或者直接返回时间戳
- 数字类型和文本类型:统一使用字符串格式
- 布尔值类型:统一使用字符串’0’和’1’来表示假和真
- 不返回Null类型数据
详情见博客:http://blog.csdn.net/zhengzhb/article/details/7296944
以上内容部分引用他出博客