前言
和我司前端小伙伴聊天的时候聊到这么一个问题,咱们调试的接口如何保证稳定可靠呢?想了一下这个问题,本篇谈一下我对这个的理解。当然,后端的语言我还是站在java语言的角度,但这个问题和语言无关,主要涉及的是思路和想法。
后端需要做的
背景
前端请求后端接口,后端最大的问题并不在于攻克什么技术难点,绝大部分情况下没什么技术难点,这件基于http、ip协议的事情,层面框架对协议的支持足够,只是实现功能保证稳定可靠的话。问题主要集中在接受一个前端的请求该如何去编排这个事情,每个事件应该本着什么样的思路落地更好。
编排处理前端:
1、如何判断此次请求是否需要处理,无法处理分为什么情况,该怎么办?可以处理又该怎么做
2、处理请求应该以什么流程进行
3、如何保证请求的结论合理且容易被前端接受
落地每一个事件:
1、确保对需求是明确的,在当前的情形下这个需求没办法进一步更加清晰
2、尽量使得每件事情一旦发生,所有可能出现的情形在你的掌握中
3、尽量选取最佳的实践进行每一个处理
4、尽最大努力追求程序的扩展性
编排处理前端 解决思路
a、如何判断此次请求是否需要处理,无法处理分为什么情况,该怎么办?可以处理又该怎么做
应用中,前端使用较多的基本是GET和POST请求,当然了,restful风格的其它类型的请求也常见。当前端的请求到达的时候,判断是否可以处理基本分为两个方面。一是当前后端是否还有处理能力,二是前端传递的意图(可以简单聊成参数)是否可以被后端接受。
是否还有处理能力涉及到限流、重试等操作,这里不做展开,感兴趣的可以自行搜索下解决方案。
是否合法这个问题,一方面是权限,一方面是参数的校验。权限这个搞过太多次了,不再叙述。重点来说下参数的校验应该以什么姿势进行。
下面是第一年的时候我校验参数喜欢使用的方式,这实在是太糟糕了,罗里吧嗦并且不清晰。事实上大多数情况下,有一个参数有问题即可拒绝前端了,下面这种方式看不懂这个人到底要干啥。
javax包下提供了很多检验参数的注解供我们使用,你可以轻松校验参数并且到底是哪个参数出了问题一目了然。
参数如果有问题将抛出MethodArgumentNotValidException异常,你可以在全局异常中将其拦截并做出个性化的处理。
有一个很重要的问题要提醒,给前端的数据可以尽量保证统一,简单,易于理解。不要每次对接一个接口都搞的风格迥异,这样给人的体验会很差。
b、处理请求应该以什么流程进行
这个需要根据前端的请求场景先做出判断,到底这属于一个什么场景?是前端给我们发送一个指令,要求后端接收到这个指令即可。或者是前端希望从后端获取到某些信息(例如从库中查询出一些数据)。再或者是前端发送指令,要求返回对这个指令的处理结果。
当你对场景做出了细致的判断,剩下的处理例程就变得简单。举例说明下,例如前端小伙伴给我发送一个指令,希望我去调用不同的系统获取一些数据,最后将数据做出汇总,但我无需汇总完数据之后响应他的请求,而是最快的速度做出响应,只要后面在他查询的时候可以通过请求标识随时获取到这一次汇总的数据即可。
那么处理的流程大概如下
1、判断这次请求有无问题,是否可处理
2、无论是否可以处理,那么立即响应前端
3、对于这次请求要处理的内容,异步做出处理和汇总
4、编写查看请求汇总结果详情的接口供前端做出详细的查询
流程如下:
落地代码大致如下:
控制层:
应用服务层:
以上的后端处理流程只是举例说明,具体场景具体分析。另外代码肯定大佬一看就有诸多问题,只作为展示思路的代码,不抠细节。
c、如何保证请求的结论合理且容易被前端接受
1、和前端的交互风格保持一致,比如:你要用http状态码表达协议状态就尽可能都用http状态码。要用响应报文中的状态码就尽可能用响应报文中的状态码。不要像下面这样:
和前端的第一个接口,你告诉他用body体里面的code做判断:
和前端的第二个接口,你又告诉他用http状态码做判断:
这样不仅对前端不友好,也不利于后端的维护,是非常糟糕的做法。
2、绝对禁止将后端乱七八糟的错误给到前端
例如下面这样的:
后端给到前端的500必须是自己cover内的500.而不是后端处理过程中出现了异常,后端也没处理扔给前端500。一旦这种情况发生,可能导致非常严重的后果。
3、保全全局,绝不因小失大
任何时候,后端的应用都不应因为未知原因崩溃掉。一条请求或者指令真出错了,就出错了,不要影响整个的应用交互。
落地每一个事件 解决思路
下面要谈的所有,围绕的都是后端做事,落地诉求的"质量"。这里的为什么要强调这个,和写出优质的前后端接口有何关系呢,关系很大,质量不行那么基本意味着就什么追求和扩展也谈不上了。
质量是软件开发第一原则,无论什么情况下,质量都要放在第一位,没有商量的余地,如果有东西让你无法保证质量,那么要及时反抗。
如果反抗无效怎么办,那也尽最大的努力。像打游戏一样,虽然可能输了,也不摆烂。
d、确保对需求是明确的,在当前的情形下这个需求没办法进一步更加清晰
在和小伙伴配合动手写代码之前,要足够了解需求。需求不明确或者不了解的情况下,无法完成任何优秀的编码和交互。技术服从业务,业务不明确的情况下,纵使技术优秀,也很难发挥什么尽如人意的作用。
e、尽量使得每件事情一旦发生,所有可能出现的情形在你的掌握中
对这一条的掌握越好,那么和前端交互出错的概率就会变小。假设写了200行代码,190行是我copy的,然后就匆忙和前端调试了,那么做出的接口的,很难让人放心。
开发者要努力让落地的程序或者代码判断都在自己的掌控中,这也是为什么明明大多数需求场景会一点点东西,糊弄糊弄就可以过去。但是很多小伙伴仍是孜孜不倦学习这个技术那个技术的原因。为的就是尽量不会出现未知问题,即便出现,也不需要慌。
f、尽量选取最佳的实践进行每一个处理
举个例子,前端要搞个查询接口,时延要求500ms。我有两个妙计,A处理耗时200ms时延即可,B处理400ms时延才能完成。
那么在不影响进度并且有余力的情况下,我相信尽可能的我还是会选择A处理。
g、尽最大努力追求程序的扩展性
应用中的 , 所有的交互也好,框架、组件也罢,讨论是否优秀,no1 的判别标准永远是扩展性。
写接口同样如此,保持尽可能好的扩展性,当有一天变更需要发生,以最小的代价完成。