顾客端后端研究开发的必修课

日期:2019-10-07编辑作者:娱乐

妈妈再也不担心我陪加班了,妈妈陪加班

  这个周末的娱乐,通用模块,让后端自检,严格客户端按照文档的要求来,妈妈再也不担心我加班了,对某些团队来说,可能根本用不着,本是想到就尝试一把而已。

 

check-docking.

check-docking is a Python package that inspect request data from client for you.

 

前言

本文从APP后端研发同学的角度,带来一些我们的思考和总结。

介绍:

此子项目仅为总结前项目的经验, 在后续项目上, 接口文档的定义入库, 结合入库的数据生成配置文件.
根据生成的配置文件, 当客户端与服务端对接时, 让程序能够自动检查客户端的传入, 并将问题返回给客户端.
该模块的目的在于减少客户端开发过程中, 在琐屑问题上对服务端的干扰. 如请求类型错误, 多参, 少参, 重参, 数据类型错误, 是否必填项等等.

接口规范

客户端和服务端通常采用Http(s) 协议,JSON(P)数据格式交互。通常定义的JSON格式如下:

{
    "code": 0, //接口状态值
    "randomcode": "1515121404158",//随机状态码
    "md5": null, //用来判断数据是否更新
    "codeMsg": "成功", // 提示语,Toast使用
    "data": { //业务数据
    }
}

我们对JSON数据格式的基本要求如下:

  1. JSON数据格式要保持良好的结构,符合标准的JSON规范
    • key必须为字符串, 使用双引号而不是单引号 , 字段命名尽量做到见名知意,命名规则建议采用驼峰命名
    • 当Value值为null时,也需要返回对应的Key ,制定协议时包含哪些字段,都需要返回
  2. data 值的数据类型为Object,不允许修改。
{
    "data": {"list":[]} //good
    "data": []   // bad
    "data": "123123"  // bad
}
  1. status需要表示状态值时,字段从1+开始,0是一种未赋值的默认状态,1:进行中,2:待支付,3:已完成,4:已取消
  2. 客户端尽量只负责展示逻辑,不处理业务逻辑。
  3. 接口返回字段除了约定的必要字段,不允许返回多余的字段。
    反例:不定义Model,直接把底层的数据库表对应的Bean返回给前端,导致多传输很多不必要的字段。
  4. 不允许拿变量命名json的key值
//good
[{"name":"书籍1","chapters":500},{"name":""书籍2","chapters":180},{...},...]
//bad
[{"书籍1":500},{"书籍2":180},{...},...]
  1. 禁止程序拼接json字符串,防止包含特殊转义字符,导致客户端解析json失败

说明:此处没有统一iOS、Android、Server的JSON解析框架

使用:

配置settings.py修改:
# check-docking配置项

IS_DATA_INSPECT = True # 仅 DEBUG 为 True 时有效
INSPECT_PROFILE = “project.check_config” # 检测依赖配置文件模块

INSTALLED_APPS 增加:
‘check_docking’,

‘check_docking.stored.django’,

下面两项非必须, 需要完成使用流程节点, 生成依赖的配置文件后启用其一.

MIDDLEWARE_CLASSES 增加:
‘check_docking.middleware.InspectMiddleware’

除了MiddleWare形式, 你也可以使用装饰器形式:

from check_docking.inspect import debug_request
@debug_request

你还可以使用工具, 从源代码中搜集数据并入库, 具体可以参看project_demo/demo/demo.py中代码.

通用设计

APP的后端系统有些设计是通用的,各APP可以相互借鉴。

  1. 通用参数
    对于一些客户端每次请求都需要的参数信息,我们暂且称之为通用参数,譬如:os、appid、appversion、channel、imei 等。对于这些信息客户端统一放在Header中。

  2. 接口签名
    接口签名的目的是保证服务端收到的请求都来自客户端,一定程度增加接口被抓取的难度。
    我们采用的方法是使用拦截器处理,客户端和服务端可以约定一些通用参数、时间戳等,前后端分别计算md5值,然后对比。
    示例代码如下:

@Override
public ActionResult preExecute(BeatContext beat) {
  HttpServletRequest request = beat.getRequest();

  String signVal = request.getHeader(HEADER_SIGN);
  if (StringUtils.isBlank(signVal)) {
    log.info("hsign is not exist.");
    RespJsonResult jsonResult = RespJsonResult.creatFailEntity(ResponseCodeConsts.AUTH_ERR_HEADER_NOT_EXIST, "guess error lowest");
    return new JsonViewResult(JsonHelper.toJSONString(jsonResult));
  }
  StringBuffer headerBuffer = new StringBuffer(100);
  for (String headerKey : headerKeylist) {
    String headerValue = request.getHeader(headerKey);
    if (headerValue != null && headerValue.trim().length() > 0) {
      headerBuffer.append(headerValue).append("_");
    } else {
      headerBuffer.append("null_");
    }
  }
  String source = headerBuffer.append("你的秘钥").toString();
  String localSign = MD5.encode(source);
  if (!signVal.equals(localSign)) {
    log.info("sign is illegal.source = " + source + ", localSign = " + localSign + ", hsign = " + signVal);
    RespJsonResult jsonResult = RespJsonResult.creatFailEntity(ResponseCodeConsts.AUTH_ERR_HEADER_NOT_PERMITTED, "guess error lower");
    return new JsonViewResult(JsonHelper.toJSONString(jsonResult));
  }
  return null;
}
  1. 配置中心
    动态化是一个APP的标配,小到一个icon的图标,大到一个页面模块的布局。特别是针对客户端这种 C/S 结构 ,各种开关、三方入口、动态链接等都需要从配置中心获取,不写死是我们的基本原则。
    另外,动态配置,从产品的角度,也可以灵活调整运营策略,达到快速试错的目的。
    整体架构见:
![](https://upload-images.jianshu.io/upload_images/2858290-5a7bcce1a9e1afbd.png)

配置中心.png
  1. 跨域问题
    跨域问题是由于javascript语言安全限制中的同源策略造成的,简单来说,同源策略是指一段脚本只能读取来自同一来源的窗口和文档的属性,这里的同一来源指的是主机名、协议和端口号的组合。
    解决跨域问题通常采用JSONP和Access-Control-Allow-Origin。
  • JSONP
    彩世界,JSONP的原理就是利用<script>标签没有跨域限制,来达到与第三方通讯的目的。
    示例代码如下:
String callback = RequestUtils.getStringPara(beat, "callback", null);
if (callback != null){
    return new JsonpActionResult(callback + "("+text+")");
} else {
    return new JsonActionResult(text);
}
  • Access-Control-Allow-Origin
    Access-Control-Allow-Origin是HTML5中定义的一种解决资源跨域的策略,他是通过服务器端返回带有Access-Control-Allow-Origin标识的Response header,用来解决资源的跨域权限问题。
    示例代码如下:
beat.getResponse().addHeader("Access-Control-Allow-Origin","www.daojia.com");
  1. 节省流量
    对于某些不经常变动的数据,特别是配置数据,譬如:城市列表数据等,我们可以将接口返回的数据缓存在客户端。服务端对比接口返回数据的md5值是否变化,如果无变化,不返回数据,客户端直接使用本地缓存数据。这样可以减少接口网络数据量的传输,节省用户流量。
    整体流程见:
![](https://upload-images.jianshu.io/upload_images/2858290-d9f5760f59be32eb.png)

数据接口缓存.png
  1. 多版本支持
    APP后端的API比前后端分离系统的API生命周期更长,一般我们的客户端在线上至少保留3-4个版本,还不包含我们针对一些特殊渠道定制的安装包。这样就要求我们后端接口在设计更加通用。
    我们通常的做法:
    对于一些修改较小的接口通过app版本号判断做数据兼容
    对于一些修改较大的接口,通过新增接口 api/v56/order/list 的方式解决
    对于业务逻辑部分,通过app版本号获取对应的实现类

  2. 接口管理
    与APP交互的后端web站点通常有多个,对此我们尽量做到统一收口。好处在于统一权限认证、接口签名、参数校验……

![](https://upload-images.jianshu.io/upload_images/2858290-5a47582e27a606a8.png)

服务端统一收口.png

8.接口文档管理
接口文档管理包括接口的描述,接口入参出参字段说明,通常这一部分文档的形成在需求详设阶段。
这一块我们做的不好,目前也没有找到比较好的方案。

本文由彩世界发布于娱乐,转载请注明出处:顾客端后端研究开发的必修课

关键词:

无论哪种类型的妹纸,你都必须乐观坚强。

       先前听说了汤唯和吴秀波主演的《北京遇上西雅图》,据反响似乎不错,羊群效应,也便团了电影票准备一...

详细>>

密林进城“住”何地?

推窗见绿 出门见园 “闲时有了好去处!” 天高云淡、水碧山青。日前,我们随着国家林业局一起来到陕西省的宝鸡市...

详细>>

2016搞笑诺贝尔奖名单出炉 生殖奖是什么梗

一年一度的科学界最大盛事马上又要来临——啊对不起,串词儿了。这不是最大盛事,这是最容易(?)和最大盛事...

详细>>

限制你眼界的不是算法,而是你和煦

现代人已经习惯通过社交网站来获取各类新闻信息。与传统媒体“你给什么我看什么”的信息获取方式不同,网络媒...

详细>>