从“上帝”视角看后端接口如何设计

这里先说说“上帝”是什么?上帝,是移动端,pc端,h5端的统称,为什么这么说呢,接口设计的最终目标,是让用户可以正常使用软硬件提供的服务。用户使用不同的端来访问接口,从而与后端发生关联关系,进而使用相关的服务。

而这些端的开发者,他们将界面与接口进行有效的结合形成一个个有机体,不同的有机体组合形成一套系统,他们使用接口,他们是顾客(自家的接口免费用,别人的接口限制或者付费用),而顾客是什么?是上帝,因此,作为“上帝”之一的移动端,有必要聊聊接口设计的东西,尽管有可能以下内容会对后端开发人员造成不适感,也要勇敢说出来。另外,也算是对接口设计思考与认知的总结。欢迎各位看官小伙伴提出一些看法,一起进步。

接口设计规范

基本性

基本性是指,接口地址符合一般性URL所具有的要素。

1.请求path
栗子

这里,以获取商品详情信息,get请求,如下:
http://www.xxx.com/Goods/getGoodsInfo?id=10025

http:是网络协议部分,该部分规定数据交互遵守的统一标准。
     现实中,可以是https,还可以是ftp或者rtmp等
xxx.com:是域名部分,该部分域名访问时,需要进行地址映射,域名->ip地址
     现实中,既可以是域名,也可以是ip地址(尤其调试阶段,各种ip地址,毕竟后端人员多,各个对接)
path:Goods/getGoodsInfo?id=10025(斜体加粗部分)
Goods:是后端功能模块,不同的功能模块,这部分对应内容有所不同。如,User信息模块,/user/getUserInfo
getGoodsInfo:是模块功能中某一具体功能对应的action(前端)或者method(后端),这里指获取商品信息的方法
    ?id=10025:?是一个特殊的分隔符,用于获取其后携带的参数,id为参数

在真实项目中,形似上述接口可能有很多,大家在使用这些接口时也习以为常,毕竟接口能正常走通。不过,不知道小伙伴们有没有发现不太合理的地方?暂且先留个问题,继续往下看

path设计原则

1.见名知意 好的path设计,使用者(开发人员或者测试人员)看到接口时,就可以很清楚的了解接口对应的功能。上述的栗子,在一定程度反映了对应的功能。以常见一些功能为栗,如下:

method Path 含义 栗子 具体说明
GET getXxxx 查找或者查询 getUserInfo 获取用户信息
POST addXxxx 提交或者增加 addOrder 增加新订单
POST modifyXxxx 修改或者更新 modifyUserInfo 修改用户信息
POST deleteXxxx 删除 deleteAddress 删除地址

这样可以减少不必要的沟通成本,记得,该沟通时一定要沟通,毕竟不是所有的设计都是那么规范。你走过的路不一定是别人的套路,有可能是血路,用同感吗?

总结,一句话,当看到接口时,我就知道对应的是什么功能

2.个性参数

个性,对于人来说,不同的人具有不同的性格特点。个性参数,对于接口而言,是不同的网络请求,使用到不同的参数。

栗子
getOrderList?orderId=1022001
getMemberInfo?memeberId=135xxxxxxxx

modifyUserInfo?
个性参数设计原则

1.见名知意 比如,oderId,goodsId。一定不要只写id,这种参数,尤其是同一个接口,涉及到多个id相类似参数。坦白说,对接接口时可能是知道具体含义,但后期维护时不一定还记得。
很有必要在id的前面加上一定的前缀
2.必传,参数设定必须要有的信息,有无默认初始,参数类型规定,统一String
3.选传,参数可有可无,有无默认初始,参数类型规定,统一String
4.注释,要清楚,每个参数是干什么用的,有具体的描述信息,无论是正常开发,还是后期维护,还是新同事接触项目,都是非常有帮助的

3.公共参数

所谓公共参数,每一个网络请求都会使用到的参数,就是公共参数或者通用参数。这些参数是请求必须要有的,这些参数具有描述性的特点

栗子
参数名称 具体说明
userToken 用户认证,用户登录成功后获取,后续请求需要携带
netType 网络类型(2G、3G、4G,WIFI)
osType 手机系统版本
osDesc 机型信息
screen 分辨率信息,获取匹配的图片
curVersion 当前版本信息
visitFrom 访问来源,如,pc端,h5,android、ios
channel 访问渠道,不同的应用市场

说明一点:现实项目中公共参数包括但不限于这些,因需求而有所不同

设计原则

公共参数设计,可以从身份认证,数据统计,问题定位,用户体验等角度进行参数设计

身份认证:如,携带token进行认证等
数据统计:如,当前使用app版本,从而控制版本。当前访问app下载所属渠道等
问题定位:如,手机系统版本,手机类型,手机分辨率等

1.必传,参数设定必须要有的信息,有无默认初始,参数类型规定,统一String
2.选传,参数可有可无,有无默认初始,参数类型规定,统一String
3.注释,要清楚,每个参数是干什么用的,有具体的描述信息。

4.响应数据

响应数据,是指客户端向服务器发送请求,正常情况下,服务器对于请求有一个具体的响应反馈,先来看下三个栗子

栗子1

针对非查询的,某种操作,比如删除,响应数据

{
    repCode:0000,
    repMsg: "删除成功",
    repTime: "20180410162022"
}
栗子2

针对查询的,比如查询某用户具体信息,响应数据(Object)

{
    repCode:0000,
    repMsg: "请求成功",
    repTime: "20180410163020",
    data:{
        userInfo:{
            userName: "小明",
            userNick: "无黄瓜不鸡蛋",
            userHeader: "http://www.xxxx.com/users/iamges/xxxx.jpg"
        //.......
        }
    }
}
栗子3

针对查询的,比如查询某用户的好友列表,响应数据(Array)

    repCode:0000,
    repMsg: "请求成功",
    repTime: "20180410163020",
    data:{
        content:[
            {
                userName: "小花",
                userNick: "绿洲一片红",
                userHeader: "http://www.xxxx.com/users/iamges/xxxx.jpg"
                //.......
            },
            {
                userName: "小白",
                userNick: "爱喝旺仔的馒头",
                userHeader: "http://www.xxxx.com/users/iamges/xxxx.jpg"
                //.......
            }
            //xxxxx更多
        ]
    }

通过以上的栗子,可以看出响应数据有共同之处

参数名称 参数含义 具体说明
repCode 响应状态码 状态码一般有0000代表请求响应成功,非0000代表失败。或者其他如200代表响应成功,非200代表失败。具体看后台设定
repMsg 响应状态值 1.当前操作的具体文字说明,如查询成功,删除成功,删除失败。2.不同的repCode对应不同的repMsg
repTime 服务端响应时间 一般会同步时间使用
data 响应数据内容 服务端返回核心数据部分
说明:
repCode状态码,除请求成功以外的各种状态,如果可以细分,尽可能细分,
repMsg状态描述,在repCode细分情况下,客户端在请求失败时,一方面,可以给予用户很好的反馈,告知用户当前操作出现问题的原因。另一方面,可以帮助开发很好的定位问题原因。总之,返回repMsg不要太任性,出来混迟早要还的哈
响应数据设计规则

1.响应的数据,其结构参照上表进行设计,具体参考栗子
2.响应的状态描述(repMsg)尽可能明确,不要太随意
3.针对json的结构,保持数据良好的阅读性以及对bean类的复用。不同的字段尽可能放到不同的对象中
4.所有的数据尽可能以单个或者多个Object形式返回。最好不要是很多个数组,比如,userName一个数组,userAge一个数组,客户端需要循环根据索引取值后。自己封装成Object
5.列表形式的数据,需要返回下一页页数,总页数

这里,有一个点,无论是请求还是响应数据,具体到每个Object内的参数,其类型最好统一为String,尤其现在大家会使用第三方的数据解析工具,比如Gson,那么,在遇到下面情况时,
Int类型:

抛出NumberFormatException(本来需要90,结果返回的是90.8)
抛出IllegalStateException(本来需要的是20,结果返回的是"20")

Boolean类型:

抛出IllegalStateException(本来需要的是true,结果返回的是"true"或者1)

Float类型:

抛出NumberFormatException(本来需要90.0,结果返回的是"90.0"或者abc)

鉴于上述情况,最好将所有Object内参数类型,接收参数统一为String
改为String后,有以下几点优点

1.容错能力增强,降低解析失败导致异常机率
2.省略掉拼接“”或者String.valueOf()
3.避免掉TextView中setText找不到资源问题

有以下缺点:

1.需要对String进行一层进行类型转换,转换为boolean或者float类型
2.对String要进行null处理,避免空指针,或者需要后台配合为null时返回""

轻量性

1.客户端app不应包含业务逻辑的处理,只负责展示

有同学会说,相比服务器,客户端没有什么复杂逻辑啊,客户端一样可以进行简单逻辑。这里,举个栗子,如下:

订单列表中,订单具有不同的状态,客户端需要根据状态值不同展示不同状态描述。

先看客户端处理,一般需要根据服务器返回的状态code或者state判断处理后,展示不同文字(有判断逻辑)
再看看服务器端,根据状态code或者state判断处理后,返回不同文字给客户端,客户端直接取出后展示(没有判断处理逻辑)

比较上述两种处理方式,会发现当需求变更时,客户端或者服务器会变更处理逻辑,但是客户端有可能需要发布新版本,搞不好,安卓段,ios端,h5端都要发布版本。而服务器更改后,各个端可以即时同步,相比之下,客户端维护端成本高,发布版本代价也很高

建议这种只是描述性的文字展示(订单状态说明或者某个操作说明或者钱包总额,提现说明,版本更新等信息)尽可能的由后台进行返回
当然,客户端根据不同状态跳转不同界面的逻辑还是要有的

2.客户端尽可能不做金额计算业务

这里,举个栗子,如下:

结算账单页面,客户端的选择项原价多少,使用优惠券多少,最终付款多少等

一般情况下,客户端会将上述项,传递给服务器,服务器去查询相关信息重新再做结算,为什么重新计算呢?避免客户端计算结果有偏差。客户端计算后直接传递支付金额给服务器看似很方便,但是风险很高,那儿怕一分钱,也有可能产生纠纷或者丢掉一个用户。这种情况下,客户端负责展示就好,涉及到金额的最好在服务器处理

安全性

1.请求,校验接口访问者合法性

证书校验,Header校验,token校验等

2.请求,涉及用户帐号、密码信息加密

一般出现在登录接口时,需要对用户帐号、密码进行加密传递,避免被拦截获取明文

3.请求,涉及金额从服务器重新核算校验
4.响应,涉及用户敏感信息加密或者隐藏

如,手机号,身份证,邮箱,支付帐号,银行卡号,地址等,在客户端展示时,将部分数据以“*”代替

拓展性

1.从响应数据结构来考虑,原本单个参数,是否有必要以对象方式返回,单个对象,是否考虑以list方式返回

兼容性

原有版本与新版本使用同一接口,新版本需要修改接口,尤其是线上还在使用情况下,原则上,尽可能不去做参数删除,优先考虑新增参数
如果需要改动的参数很多,可以考虑使用新接口

其他优化

1.同一界面,是否可以将多个接口合并

考虑到资源,电量,频繁的创建网络请求等,考虑是否合并

2.不同界面,是否可以将多个接口合并

有时某个接口只是单纯的获取一项信息,而该信息可能在很多地方使用到,这时考虑是否在某个接口统一返回放到缓存中

3.减少网络请求

接口获取数据,根据本地md5值与服务器md5值改变,来判断是否有更新,没有则取缓存,有则更换最新。首次md5为null

4.接口参数名精简,做到见名知意

尽可能使用少量单词书写参数

5.无用参数清理

这个说起来很容易,操作起来不见得。上面说过,尽可能不去做删除参数操作,所以,凸显出接口文档的重要性,每个接口,每个参数都有相应的记录说明,无用参数清理就变得简单些

6.列表带图时,显示小图,详情,显示大图

设计接口时需要考虑到图片显示问题,毕竟图片展示是耗流量的大户,即便流量不是问题,大图展示时比较耗时,所以,流量消耗,时间消耗,是需要考虑的

猜你喜欢

转载自blog.csdn.net/rockykou/article/details/79998084