程序笔记   发布时间:2022-06-07  发布网站:大佬教程  code.js-code.com
大佬教程收集整理的这篇文章主要介绍了[接口设计]从客户端的角度设计后端的接口大佬教程大佬觉得挺不错的,现在分享给大家,也给大家做个参考。

前言

接口设计规范

一. 接口示例

接口描述:用户登陆成功后,或进入个人中心时会获取一次用户信息

@H_419_18@ @H_419_18@
URI 方法
/userinfo GET

请求参数

@H_419_18@ @H_419_18@
名称 必填 备注
ID 用户ID

响应参数

@H_419_18@ @H_419_18@ @H_419_18@ @H_419_18@
名称 类型 备注
ID String 用户IDname String 姓名,例:张三age String 年龄,例:20

Json示例

{
    "code":200,"msg":"成功","time":"1482213602000","data": {
        "ID":"1001","name":"张三","age":"20"
    }
}

二. 基本规范

1.通用请求参数

@H_419_18@ @H_419_18@ @H_419_18@ @H_419_18@ @H_419_18@ @H_419_18@ @H_419_18@ @H_402_16@model @H_419_18@ @H_419_18@ @H_419_18@
字段名称 说明
version 客户端版本version,例:1.0.0token 登陆成功后,server返回的登陆令牌tokenos 手机系统版本(Build.VERSION.RELEAS)例:4.4,4.5from 请求来源,例:androID/ios/h5screen 手机尺寸,例:1080*1920 机型信息(Build.MODEL),例:Redmi Note 3chAnnel 渠道信息,例:com.wandoujianet APP当前网络状态,例:wifi,mobile;部分接口可以根据用户当前的网络状态,下发不同数据策略,如:wifi则返回高清图,mobile情况则返回缩略图appID APP唯一标识,有的公司一套server服务多款APP时,需要区分开每个APP来源

2.请求Path,http://www.online.com/api/ [path]

@H_419_18@ @H_867_10@method @H_419_18@ @H_419_18@ @H_419_18@ @H_402_16@modifyXxx @H_419_18@
操作行为 Path
查找 GET getXxx增加 POST addXxx/submitXxx修改 POST删除 POST delXxx

示例

@H_419_18@ @H_867_10@method @H_419_18@ @H_419_18@ @H_419_18@ @H_402_16@modifyPwd @H_419_18@ @H_419_18@ @H_419_18@ @H_419_18@
操作行为 Path
获取用户信息 GET getUserInfo增加收货地址 POST addAddress修改密码 POST删除收货地址 POST delAddress登陆 GET login发送短信验证码 GET sendSms订单支付 POST orderPay

3.响应数据

@H_419_18@ @H_419_18@ @H_419_18@ @H_402_16@msg @H_419_18@ @H_419_18@
字段名称 说明
code 响应状态码,200:成功;非200:失败 请求失败时的messagetime 服务端时间戳,单位:毫秒。用于同步时间data 数据实体

code=200时,msg=登陆成功/修改成功/提交成功;如果需要Toast,可以直接使用msg。
code!=200时,msg=错误提示信息;比如login接口,”账号或密码错误”,”账号不存在”类似这些的业务提示文案放在msg字段,客户端直接Toast就可以了。不过需要提醒后端同学,错误提示不能自己觉的什么合适就提示什么,要按需求文档来提供,或和PM确认。

// Json
{
  "code":200,"data": {
    "name":"张三","age":"20"
  }
}  

// model.java
public class Model {
     public String name;
     public String age;
}
// Json
{
    "code":200,"data": {
        "@R_419_6818@":["张三","李四"]
    }
}   

// model.java
public class Model {
    public @R_419_6818@<String> @R_419_6818@;
}

请求参数

@H_419_18@ @H_419_18@ @H_419_18@
名称 必填 备注
pageNum 当前第几页,例:1,2,3pageSize 每页条数,例:10

响应数据

// Json
{
    "code":200,"李四"],"@R_907_10586@l":"10"
    }
}   

// model.java
public class Model {
    public @R_419_6818@<String> @R_419_6818@;
    public String @R_907_10586@l;
}

4.命名规范

  • 统一命名:与后端约定好即可(php和Js在命名时一般采用下划线风格,而Java中一般采用的是驼峰法),无绝对标准,不要同时存在驼峰”username”,下划线”phone_number”两种形式就可以了。

  • 避免冗余字段:每次在新增接口字段时,注意是否已经存在同一个含义的字段,保持命名一致,不要同时存在”username”,”username”,”uname”多种同义字段。

  • 注释清晰(重要):每个接口/字段都需要有详细的描述信息,很多时候接口体现业务逻辑,是团队中很重要的文档沉淀,同时,详细的接口文档,可以帮助新人快速熟悉业务。具体示例如下

@H_419_18@ @H_419_18@
URI 方法
/userinfo GET
@H_419_18@ @H_419_18@ @H_419_18@ @H_419_18@ @H_419_18@ @H_419_18@
字段类型 字段名称 说明
Boolean isVip 是否时Vip用户,1:是,0:否金额 realPay 订单实际付款金额,单位:元时间 payTime 订单付款时间,单位:毫秒日期 payDate 订单付款日期,格式”yyyy-MM-dd”状态 status 订单状态,1:进行中(payDate不返回),2:待支付(payDate返回),3:已支付(payDate不返回);(bool以1/0表示,状态从1+开始)

5.统一定义String字段类型

// Json
{
    "name":"张三","isVip": true,"age":20,"money": 10.5
}

// Model.java
public class Model {
    String name;
    Boolean isVip;
    int age;
    float money;
}
{
    //如果传true,false以外的数据,就会解析失败
    "isVip": 20
    "isVip": 
}

解析报错:

(1)java.lang.IllegalStateException: Expected a Boolean but was numbER
(2)com.Google.gson.stream.MalformedJsonException: Unexpected value
  • Int类型字段
{
    "age": 20.5
    "age": abc
    "age": ""
    "age": 
}

解析报错:

(1)java.lang.numberFormatException: Expected an int but was 20.5
(2)java.lang.IllegalStateException: Expected an int but was StriNG
(3)java.lang.numberFormatException: empty String
(4)com.Google.gson.stream.MalformedJsonException: Expected value
  • float类型字段
{
    "money": abc
    "money": ""
}

解析报错:

(1)java.lang.numberFormatException: For input String: "abc"
(2)java.lang.numberFormatException: empty String
  • 修改Gson源码,对于字段解析失败的异常进行捕获,保证model解析完成,非正常解决方案,修改源码后Gson库就不能随便更新了,获取替换其他Json解析库也变的不方便
  • 自定义JsonDeserializer,比较正常的解决思路。
public class IntegerDefaultAdapter implements JsonDeserializer<Integer> {
  @OverrIDe
  public Integer deserialize(JsonElement Json,Type typeOfT,JsonDeserializationContext context)
      throws JsonParseException {

      // 如果Integer类型的字段,进行一次类型转换
      try {
          return Integer.parseInt(Json.getAsString());
      } catch (numberFormatException E) {
      }
      return -1;
  }
}

String Json = "{name:@R_419_6818@en,isVip:true,age:abc,money:1.0}";
Gson gson = 
new GsonBuilder().registerTypeAdapter(int.class,new IntegerDefaultAdapter())
.create();
Model model = gson.fromJson(Json,Model.class);// age字段解析出来为-1
  • 将APP接收数据的类型定义为容错能力更强的String(推荐)。
{
    "name": "abc"
    "name": "20"
    "name": "10.2"
    "name": "true"
}

优点:

  • 容错性强,规避因脏数据引起的数据解析失败。
  • age,money这些字段大部分情况下都是直接展示,此时便可省去拼接 “”,或String.valueOf()等步骤。另外假设此时将age字段定义为int类型,很容易就会直接调用textVIEw.setText(agE),那么这个age就会当成resID去执行,导致资源找不到报错,定义为String可以避免此类错误。

注意事项:

  • Boolean类型数据,统一返回1(true)和0(false),客户端做一层容错判断,只有1才为true,其他非1,解析失败的情况均为false,例:

    if(!TextUtils.isEmpty(isVip) && "1".equals(isVip)) {
        return true;
    }
        return false;
  • status类型字段从1+开始,和Boolean类型(0否,1是)区分开。”0”的含义有2种,(1)非0即为真,所以0即表示false;(2)”0”是一种未赋值的默认状态。假设此时用0表示状态1,那么就很难判断出到底时数据解析失败,使用默认值0,还是说逻辑走通并赋值为0。例:orderstatus,1:进行中,2:待支付,3:已完成。

  • int,float类型数据,如果不是直接展示的话,需要做一次类型转换,注意捕获异常,在解析失败的情况下,使用default值。

    int defaulTint = -1;
    try {
    defaulTint = Integer.parseInt(agE);
    } catch (numberFormatException E) {
    e.printstacktrace();
    }
    return defaulTint;

6.上传/下载接口,根据md5校验数据完整性

  • 上传,下载文件/图片时,除了file本身,还要携带该file的md5,在传输过程中可能丢失部分数据,导致文件损毁,所以需要通过md5值进行完整性校验。
  • 上传成功后,正常情况后端只需要返回code表示成功/失败,在开发阶段,可以让后端将上传成功后的图片url返回,这样当我们调用完接口以后,就可以通过该url字段查看图片是否上传成功,存储的尺寸大小,模糊度等,就不用每次粘着后端帮忙看请求结果了,这个思路同样通用于其他接口,不过上线后需要将这个不必要的字段去掉。

    {
      "code":200,"data": {
          "url":"http://www.online.com/path/pic.jpg"
      }
    }

7.避免浮点型计算

8.Json数据保持良好结构

{
    "userID"...
    "username"...
    "userPhoto"...
    "orderID"...
    "orderType"...
    "addressID"...
    "addressname"...
    "addressDetail"...
}
{
    "user":{
        "ID"...
        "name"...
        "photo"...
    }
    "order":{
        "ID"...
        "type"...
    }
    "address":{
        "ID"...
        "name"...
        "detail"...
    }        
}

三. 瘦客户端

  1. 客户端尽量只负责展示逻辑,不处理业务逻辑

  2. 客户端不处理金额的计算

  3. 客户端少处理请求参数的校验与约束提示

    • 在发送请求前,客户端校验密码规则,如果不符合,则不发送请求。优点:规则不满足时,可以减少不必要的请求。缺点:客户端写死校验逻辑,密码规则变化时,客户端需要发版。
    • 客户端只判断null,和最短位数限制,其他校验规则交由后端处理。优点:灵活性最好。缺点:后端压力大,校验请求多。
    • 后端在通用配置的接口返回正则表达式,客户端获取后进行正则校验。优点:具有一定灵活性。缺点:开发,调试成本较高。(推荐:即使出问题,也可以清除配置,回退到第2个方案)

四.扩展性

  1. 文案与图片

  2. 数据列表化:尽量用@R_419_6818@(key,value)的数据格式定义类似列表的界面


    @R_419_6818@.png

     

方案1:客户端在写xml的时候将左侧的”姓名”,”性别”,”年龄”写死,右侧的具体数据从Json解析获得

{
    "name": "张三","sex": "男","age": "20岁","nickname": "小张"
}

方案2(推荐):将左侧的title和右侧的value,以@R_419_6818@(key-value)的数据形式进行下发,优点:左,右侧文案灵活配置,后期如果需要扩展,新增或删除一个条目,都可以通过后端控制。不过采用这种形式,也需要虑实际场景,对于变化不那么频繁,数据item较少,较固定的情况下其实没有必要设计的太灵活,只会增加开发成本。

{
    "userInfos":[
    {
        "key":"姓名","value":"张三"
    },{
        "key":"性别","value":"男"
    },{
        "key":"年龄","value":"20岁"
    },{
        "key":"昵称","value":"小张"
    }]
}

3.用flag替换Boolean:一般情况下,一款APP都会有config接口,用于获取一些常量文案,通用配置等信息,会有很多类似开关的字段,如:”isNew”,”isVip”,”isShowBalance”等等。

{
    "isNew":"1",// 是否是新用户
    "isVip":"1",// 是否是VIP用户
    "isShowBalance":"1",//是否显示侧边栏余额模块
}

优化方案:通过二进制第1位表示”isNew”,二进制第2位表示”isVip”,二进制第3位表示”isShowBalance”。如果有其他新增状态,不需要新增字段,就需要改变返回的数据即可。

{
    "flag":"7"// 二进制:111,表示3个状态都为true
    "flag":"5"// 二进制:101,表示isNew,isShowBalance为true,isVip为false
}
long flag = 5;
System.out.println("bit=" + Long.toBinaryString(flag));
System.out.println("isNew=" + ((flag & 1) == 1));
System.out.println("isVip=" + ((flag & 2) == 2));
System.out.println("isShowBalance=" + ((flag & 4) == 4));

bit=101
isNew=true
isVip=false
isShowBalance=true

五.安全性

  1. 响应数据中包含用户隐私的字段数据,需要加*号。如:手机号,身份证,用户邮箱,支付账号,邮寄地址等。

    {
     "phone":"150*****000","IDCard":"3500**********0555","email":"40*****00@qq.com"     
    }
  2. 请求参数中包含用户隐私的字段参数,如:登陆接口的密码字段,需要进行加密传输,避免被代理捕捉请求后获取明文密码。

  3. 客户端和服务器通过约定的算法,对传递的参数值进行签名匹配,防止参数在请求过程中被抓取篡改。密钥记得放到so中,放在java层太不安全,so中要进行keystore反向签名校验,避免so被获取后直接调用获取算法。

六.兼容性

  1. 接口/字段的删除,修改要谨慎:
  2. @H_483_298@md5缓存的兼容性:

七.性能优化

  1. 合并接口

  2. 字段精简

     {
       "orderDescription" >> "orderDesc"
       "oldpassword" >> "oldPwd"
       "longitude" >> "lng"
       "latitude" >> "lat"
     }
  3. @H_524_4@md5缓存


    @H_15_538@md5.png
  • 无用字段清理

  • 图片裁剪服务

  • 局部刷新

  • wifi与移动网络的区别对待

  • 八.体验优化

    1. 通过预加载降低对网络的依赖

          {
               "md5"... // 校验所有item的detail,只有在新订单,或订单完成后移除的情况下,md5才会变化
               "order@R_419_6818@":[{
                   "ID"...
                   "status"...
                   "detail":{ // detail中尽量只保留变化情况较少的字段,避免md5频繁变化,如status就移出到item中存放
                       "type"...
                       "desc"...
                   }
               },{
                   "ID"...
                   "status"...
                   "detail":{
                       "type"...
                       "desc"...
                   }
               }]
          }

    转:http://blog.csdn.net/BaiHuaXiu123/article/details/54015240

    大佬总结

    以上是大佬教程为你收集整理的[接口设计]从客户端的角度设计后端的接口全部内容,希望文章能够帮你解决[接口设计]从客户端的角度设计后端的接口所遇到的程序开发问题。

    如果觉得大佬教程网站内容还不错,欢迎将大佬教程推荐给程序员好友。

    本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
    如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。