从零开始的Android新项目9 - 前端用后台接口设计(教你更好地项目协作)

这回来讲讲后台接口的设计。

可能有同学会觉得后台的接口和我们大前端开发有什么关系?试想一下,在碰到一些不合理的接口设计的时候,你们开发是否觉得很别扭——需要为了坑爹的接口写很多脏代码引坑?甚至,这么开发出来的页面,体验也会很差?我们不是说硬无理要求后端接口按照前端业务去封装,而是说为了项目更好地发展,为了用户能有更棒的体验,应该有讨论商量的空间。一些差劲的设计,应该被拒绝。

本文使用前端来指代 Android、iOS 以及 Web。

本文不是教大家撕逼的(赶紧撇清关系)。

全局

全局指所有接口统一的规范。

请求头

应该使用http header来放置通用性的参数,比如:

  • APPID(Android/iOS/H5)
  • APPVER(版本号)
  • APP-BUILD-NUM(内部小版本号)
  • TOKEN
  • NETWORK(网络环境)
  • LANGUAGE(语言)
  • 等等

前端使用 POST 键值对方式提交给后端,可以使用 RawJSON 格式。
Content-Type 设为 application/x-www-form-urlencoded 或者 application/json

全局响应格式

响应格式应该统一,方便前端做统一的处理,尤其是数据字段,应该统一放在一个map里面。

名字 类型 详细描述
status_no INT 状态码
status_msg STRING 状态信息
data MAP 响应内容
time INT 响应时间戳

状态码

全局应该定义统一的状态码(status_code),而不应该每个接口单独去定义。

具体规则可以自行定义,比如0为正确,负数为错误。

常见的错误状态码有

  • 普通异常
  • token不合法,需要重新登录
  • 重复登录
  • 需要完善个人信息
  • 第三方账号登陆,需要绑定官方账号
  • 请求头不合法(版本号,APPID等)
  • 数据解密错误

可以根据错误类型划分使用的区域段,如登陆系列使用 -1000 到 -1999 区域。

如此定义后,前端可以进行全局的统一处理,如重复登陆则踢出用户。

错误信息

除了特殊的错误信息——如重复登录、token不合法这些状态码对应的,以及无网、没数据这些,对于通用的异常,应该由后台返回错误信息。

统一data字段

data 字段应该统一放在一个 map 内,里面存放具体的响应信息。

Scheme

全局定义统一的 scheme(Deeplink),方便前端进行跳转。

前端只需要定义自己唯一的 Deeplink 并进行注册即可(scheme 和 host)。

具体使用 REST 风格(如 markzhai://article/XXX),还是普通的 urlencode (如 markzhai://article/?id=XXX&redirect_url=XXX)可以根据自身需求定义。

使用 REST 风格的一个顾虑是可能 scheme 本身并不是基于资源的,而是基于类型、行为等,所以 urlencode 可能更通用,但相应地基于 Deeplink 的资源索引会希望你是无状态的 REST 风格。

回传 or 状态码

应该使用回传还是状态码呢?比如点赞消息,是应该回传一个 status_code,0则表示点赞成功,还是应该回传现在的赞状态呢?

其实这两者对于后台的性能来说,是几乎没有影响的,因为取得的只是修改的字段的最后结果。但是对前端来说,差别就有了——需要维护状态。

举一个例子:
A 和 B 是两个用户,B 关注了 A,A 没有关注 B。
A 看 B 的主页的时候,显示关系是 未关注,此时 A 点击了关注,如果没有回传信息,那么我们只能把关系刷新为 已关注,而没有足够的信息去刷新为 互相关注。否则就需要前端去做恶心的逻辑(后端一开始用户关系就需要传 B 关注了 A),根据原来的关系去做切换,还要在失败的时候刷回原来的状态。

一些有丰富经验的后端会在这种接口使用回传,因为他们知道区别。

模块vs页面

在后台的接口设计上,又分为了按页面以及按模块。

按页面的接口尽可能让前端一个页面只请求一次,一次返回所需要的全部信息;按模块的接口在后端定义自己的业务模块如用户、Feed、标签、搜索等,并尽量避免模块间的耦合。

从后端角度来说,按模块当然是更好的(只需要划分地够细就好),到时候需求有什么变更,让前端自己去改变接口的组合就好,自己高枕无忧。但从前端的角度来说,接口的组合涉及到异步之间的关系,尽管RxJava这样的响应式编程框架让异步简单了很多,但仍然希望可以避免,更严重的是,多次接口请求会让前端的体验变差,并行接口的影响稍小,而一些有前置后置关系的接口则麻烦比较大,一个接着一个请求,会让用户等很久。即便是并行接口,有时候页面的渲染仍然需要所有接口数据返回后才可以进行。

但如果让后端按照页面去套,这样在后端其实一样有性能的损耗,需要一个页面接口去单独调用各个模块的接口,然后进行组合。

究竟如何选择呢?笔者认为在服务器性能足够的前提下,后端应该尽量减少页面请求次数,尤其是有依赖关系的串行请求。另一方面,在一些影响不那么大的页面,则可以由前端自行进行接口组合(比如上面是用户主页的用户展示,下面是该用户的 feed 列表)。

另外,如果你们有一个好的设计师,那么他应该会贯彻一个地方只应该以一样东西为主体,而不应该去把乱七八糟的东西拼凑在一起。

分页信息

现代的前端交互上,已经很少会有页码显示了,所以很多后端的列表页接口中,就没有带上了分页的信息,而改让客户端去维护请求的页码。

那么,分页信息在接口中,真的就没有存在的必要了吗?其实未必。

为什么需要分页信息

页面大小(pageSize)可能改变(无论是前端自己的配置亦或是后台修改),如果仅由客户端维护页码,那么下次请求下一页就会出错,除非客户端带上自己上次的页面大小。

如果客户端不知道当前页码和总页数,就无法在请求完判断底部应该显示上拉加载更多还是没数据了,导致必须再请求一次,根据是否返回 list 以及数据是否为空去进行判断。

另外,由后端返回页码也避免了客户端修改页码出错的可能。

但对后端来说,这些信息的获取却意味着更大的计算和I/O资源损耗。

折中办法

折中地,可以让后端返回一个 has_more 字段,这样可以避免最后一次不必要的请求(尤其是数据都不够显示满一页的情况下),体验会好很多。尽管这样仍然无法避免页面大小改变的问题。

配置

一些后台喜欢让让前端写限制逻辑,比如搜索的关键字限制,各种过滤逻辑。

咱们先不提让前端写死这些逻辑的灵活性问题(客户端和网页不同,不能那么方便地发版本,即便是网页,改代码发版本就不用测试了吗?出了问题你背?)。前端的输入真的可以信任吗?且不谈代码可能写的不够严谨导致输入跳过了检查,用户还能root、越狱,甚至可以反编译客户端或者直接模拟请求。

所以良好的配置检查应该有两种

  • 后端下发配置字段,前端根据字段去做对应检查。好处是减少后台压力,坏处是无法保证安全性。
  • 后端收到请求自行检查过滤,如果出错则返回错误信息给前端显示。

毋庸置疑,后者更好。

另外,再说说灵活性。今天可能限制3个字,明天产品需求可能就是4个字,现在产品/运营说不会改,到时候难道就真的一定不会改吗?

空字段

一些空字段,如果没有,服务端应该返回一个空的默认字段 比如 String 用"",int 用 0,Object 用 {},Array 用 [],这样减小前端校验某些校验漏了出现错误的情况。

                    ---- 由三帅泥阿布补充

我个人认为这样本身对流量损耗不大,且确实避免了很多可能的异常,是个很好的意见。当然了,正如后端不应该相信前端的输入一样,前端也不能相信后端数据的完备性,仍然还是需要悲剧地去校验。

教训

  • 不要相信什么以后重构,接口现在这么说,以后他会告诉你,没法兼容老版本所以只能这样了(甚至搞出两套规则让你同时兼容)。

  • 不是说后端就是老大。大家的目标都是为了项目能做好,而现在通常前端的压力比后端更大(前端写得头昏脑花,后端网上东逛西逛),所以在不会很大影响性能的前提下,应该满足前端的合理需求。体验为先。(硬气一点,老大应该挺你,甚至亲自去撕逼,大不了找CTO)

  • 接口的频繁修改要向上反馈,测试数据不满足要求也要及时提出。咱们不做背锅侠。

  • 灵活,灵活。做各种需求的时候,想一想,这儿会不会改变?就算现在不会变,以后就不会变吗?比如抽屉里的入口,是不是要做成可配置的?多问问,实现上尽量灵活。

总结

本篇讲了很多通用的后端接口设计问题。帮助大家在面对一些不合理的接口设计时,能进行友善的讨论(撕逼),让项目能做得更好。欢迎各位在评论里或者通过邮件(zhaiyifan56@gmail.com)补充其他点,我会标注出来源。


欢迎加入QQ群:568863373。

欢迎关注我们的公众号:魔都三帅,欢迎大家来投稿~只需要是未在微信平台上发布过的技术相关类文章都可以哦(不局限于任何语言和平台)。

公众号
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,847评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,208评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,587评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,942评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,332评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,587评论 1 218
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,853评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,568评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,273评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,542评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,033评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,373评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,031评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,073评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,830评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,628评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,537评论 2 269

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 170,568评论 25 707
  • 前言 兵马未动,粮草先行。在一款APP产品的各个版本迭代中,兵马的启动指的是真正开始敲代码的时候,粮草先行则是指前...
    listen2code阅读 17,902评论 51 220
  • 片段 二: 选自《非暴力沟通》 R:原文 非暴力沟通第二个要素是感受。心理学家罗洛.梅认为”成熟的人十分敏锐,就像...
    vege81阅读 195评论 0 0
  • 我曾经和一个人约定好了,若他死了,我便同他离去,在另一个世界继续做他的密探。 但是后来我违约了。 魔种的生命是要比...
    帅气的济南蜀黍阅读 2,842评论 0 8
  • 你也许不会相信,我常常想象你是多么美好,多么可爱,但实际见了你面的时候,你比我想象的要美好得多,可爱得多。 你不能...
    青一墨阅读 586评论 0 2