如何把一个接口设计好?

如何,一个,接口,设计 · 浏览次数 : 1150

小编点评

**如何设计一个接口?** 1. **命名规范:**清晰易懂地命名接口、方法、入参和出参。 2. **参数校验:**在接口定义时,对参数进行全面的校验,包括空值、长度、枚举值等。 3. **监控/性能:**监控接口性能和异常报警,并设置合理的安全超时时间。 4. **日志记录:**记录接口调用过程中的所有关键信息,方便维护和调试。 5. **异常处理:**提供多种异常处理机制,例如具体的异常、流式处理、以及处理运行时错误等。 6. **异步接口:**考虑使用异步处理机制,以提高性能。 7. **注释:**撰写清晰易懂的注释,帮助理解和维护代码。 8. **降级/限流:**在基础服务不可用时,考虑降级处理或限流处理请求。 9. **安全:**关注数据安全、代码安全、线程安全等方面。 10. **沟通:**与技术leader沟通接口设计思路和问题,及时了解技术需求,并进行沟通协商。

正文

如何设计一个接口?是在我们日常开发或者面试时经常问及的一个话题。

很多人觉得这不就是CRUD,能实现不就行了。单纯实现来说,并非难事,但要做到易用、易扩展、易维护并不是一件简单的事。这里并不强调一些个接口设计的原则或者设计方法,仅从如何设计一个好的接口出发,简单讨论。

1、命名规范

我们写代码,不仅仅是为了实现当前的功能,也要有利于后面的维护。所谓的维护,就是代码不仅仅是写给自己看的,也是给别人看的。所以接口定义要清晰易懂、命名规范。

除了接口、方法、出入参命名规范,也要注意代码规范问题。一开始接触到各种代码坏味道的小伙伴,大多都会觉得这些规范很多余、很烦人,但实际上,这些好的编码习惯是让大家都能按照基本规约开发,易于阅读易于维护的基础。

在接口定义时,也请注意接口功能的单一性。其实这也是微服务的一些思想,接口功能的单一职责、明确简单。比如登录接口,它做的事情就是校验账户名和密码相关;订单服务、积分服务、商品信息相关的接口都是划分开的。

2、参数校验

入参出参校验是每个程序员必备的基本素养。你设计的接口,必须先校验参数。比如入参是否允许为空、入参长度要求、入参是否在枚举值范围内等等。日常开发中,很多低级bug都是不校验参数导致的。

提到参数,就必须提到接口状态和错误码。无论是失败还是成功,一个完备的接口都应该告诉调用方返回信息。如果接口失败,具体失败的原因是什么,这就需要定义明确的错误码和对应描述。同时,尽量对报错信息进行封装,不要直接将服务端异常信息抛出去。

3、监控/性能

如何评判一个接口的性能就必须要有监控,这对于服务端监视接口性能和异常报警至关重要。调用次数、可用率、TP99、TP999等监视指标,极其重要的核心接口,还需要细分至秒级监控加以标识。

一个接口的性能不单单只看自己业务逻辑,外部远程调用也是消耗性能的重要部分。如果你调用第三方接口或者远程服务,就需要考虑异常和超时。如果异常了,怎么处理,是重试还是当作失败还是告警处理。如果重试,重试几次?这就需要站在业务角度思考这个问题。这些措施也是直接影响当前接口性能。

提高性能的利器还可以考虑缓存。缓存用得好,可以承载更多的请求,提升查询效率,减少数据库的压力。但是使用缓存需要考虑缓存和数据库一致性保证、缓存击穿等问题。

4、日志

接口的关键代码,要有日志的保驾护航。首先日志级别需要合理使用:error > warn > info > debug。

其次日志信息包含哪些呢,核心代码块调用前的入参打印、接口调用后的异常捕获日志等。需要注意的是,如果日志中涉及比较大的JSON富文本,请使用log.isInfoEnable(),在高并发和复杂log信息拼接的情况下,使用这种标准的方法输出log能够省去不小的系统开销。另外,如果构造log信息的过程需要大量字符串操作,建议使用StringBuilder来完成字符串拼接。

5、异常/超时

实现一个好的接口,离不开优雅的异常处理。比如异常匹配的顺序,优先捕获具体的异常;使用流时记得使用finally关闭流资源;

对于运行时错误,比如数据边界越界、空指针也在日常开发中出现,该判断、该校验的还是一项不能少哦。

超时问题也经常会导致接口不可用。设置合理的超时时间,也是在保护你的接口。超时一般与重试搭配使用,不过请注意,设置超时时间时,需要充分考虑你的上下游设置的超时时间。比如一个请求率先访问你的上游,而你的上游设置的超时时间是500ms,上游调用你的接口,但你设置的超时是2000ms,这其实就是无效超时时间。

对于接口耗时优化,也是有一些手段的,比如远程串行改为并行调用、单次调用改为批量调用等等。但请注意尽量不在循环或者事务里远程调用。

6、异步

接口有些场景,使用异步更合理。举个简单的例子,对于一些运营操作的接口,往往需要记录对应操作的操作日志,记录下是谁在什么时间操作了什么对象,便于追踪“事发现场”。但是记录操作日志并不在接口主流程上,记录操作日志是否成功失败也不应该影响正常主流程的执行,这个时候就应该考虑用消息队列等方式进行异步解耦。

7、注释

可以说,注释也是良好代码的重要组成部分。有些人,一直相信show me the code,却不想写一行注释,认为没有必要。但是你无法保证代码逻辑一直清晰、高效。如果是比较复杂的话,就建议把注释写清楚,这对于后续维护和缕清代码逻辑很重要。

8、降级/限流

如今的请求调用基本都是分布式调用链路,当分布式系统中某个基础服务不可用时,就会最终导致整个系统不可用,所以当下游系统或者自身服务出现问题时,一定要考虑降级。如果做的更完备的话,还可以考虑熔断。

同时,针对高并发的流量洪峰接口,必须考虑限流应对超出系统的承载能力挑战。限流措施也同样可以限制爬虫,保护系统,丢弃多余的请求。

9、安全

这里说的安全,范围可太大了。比如线性安全,很多人反手上来就是HashMap,因为它是非线性安全的,可以考虑高并发下的ConcurrentHashMap。

如果前端重复请求,你的逻辑如何处理?是不是考虑接口去重处理(有时候是防刷处理)。简单点,可以使用redis防重处理,同样的请求,一定时间间隔内进行过滤。当然,对于一些并发不高的接口,比如转账类接口,推荐使用数据库主键或者唯一索引。

如果消息队列出现重复消费的情况,你的业务逻辑怎么控制?是不是考虑幂等性校验。

防重主要为了避免产生重复数据,把重复请求拦截下来即可。而幂等设计除了拦截已经处理的请求,还要求每次相同的请求都返回一样的结果。不过很多时候,它们的处理流程和方式是类似的。

还有一些其他安全方面的考虑,比如读写分离、代码锁的粒度控制、数据加密等等。

10、沟通

为什么要有沟通?又为什么把沟通放在最后呢?遇到一些技术难题,跟技术leader对齐方案。实现需求的过程中,有什么问题,需要及时跟产品沟通。需要跟客户端对齐接口,一定不能上来就自己埋头把接口定义完了。种种场景,学会沟通是非常重要的,有效、高效沟通不仅会带来愉悦心情,开发起来很顺畅,也会提高人际关系。

好啦,以上就是根据自身经验,对“如何设计一个接口?”问题的小小回答,如有不足,敬请指教。

作者:京东零售 李泽阳

来源:京东云开发者社区 转载请注明来源

与如何把一个接口设计好?相似的内容:

如何把一个接口设计好?

如何设计一个接口?是在我们日常开发或者面试时经常问及的一个话题。很多人觉得这不就是CRUD,能实现不就行了。单纯实现来说,并非难事,但要做到易用、易扩展、易维护并不是一件简单的事。这里并不强调一些个接口设计的原则或者设计方法,仅从如何设计一个好的接口出发,简单讨论。

互联网大厂的缓存策略:抵抗超高并发的秘密武器,已开源!

大家好,我是冰河~~ 最近,有小伙伴私信我:冰哥,我最近出去面试,面试官问我如何设计缓存能让系统在百万级别流量下仍能平稳运行,我当时没回答上来。接着,面试官问我之前的项目是怎么使用缓存的,我说只是缓存了一些数据。当时确实想不到缓存还有哪些用处,估计这次面试是挂了。冰哥,你可以给我讲讲互联网大厂项目是

为什么要把类设置成密封?

前几天笔者提交了关于FasterKvCache的性能优化代码,其中有一个点就是我把一些后续不需要继承的类设置为了sealed密封类,然后就有小伙伴在问,为啥这个地方需要设置成sealed? 提交的代码如下所示: 一般业务开发的同学可能接触密封类比较少,密封类除了框架设计约束(不能被继承)以外,还有一

从Kafka中学习高性能系统如何设计

相信各位小伙伴之前或多或少接触过消息队列,比较知名的包含Rocket MQ和Kafka,在京东内部使用的是自研的消息中间件JMQ,从JMQ2升级到JMQ4的也是带来了性能上的明显提升,并且JMQ4的底层也是参考Kafka去做的设计。在这里我会给大家展示Kafka它的高性能是如何设计的,大家也可以学习相关方法论将其利用在实际项目中,也许下一个顶级项目就在各位的代码中产生了。

手动实现BERT

本文重点介绍了如何从零训练一个BERT模型的过程,包括整体上BERT模型架构、数据集如何做预处理、MASK替换策略、训练模型和保存、加载模型和测试等。 一.BERT架构 BERT设计初衷是作为一个通用的backbone,然后在下游接入各种任务,包括翻译任务、分类任务、回归任务等。BERT模型架构如下

关于面向对象的方法并行执行的问题

LabVIEW的从同一个类实例化的多个对象如何执行各自的方法呢? 这几天跟同事讨论到LabVIEW的面向对象编程中,如果我设计的一个类有一个方法比较耗时,那么当我实例化多个对象时,那么这个耗时的方法是怎么执行的呢?是各自并行执行还是,必须等某一个对象的方法调用完,接下来调用第二个对象的该方法呢? 接

前端使用 Konva 实现可视化设计器(14)- 折线 - 最优路径应用【代码篇】

话接上回[《前端使用 Konva 实现可视化设计器(13)- 折线 - 最优路径应用【思路篇】》](https://www.cnblogs.com/xachary/p/18238704),这一章继续说说相关的代码如何构思的,如何一步步构建数据模型可供 AStar 算法进行路径规划,最终画出节点之间的...

物联网 IOT 设备如何脱离信息孤岛?

目前在家庭物联网这一块,绝大部分的电子消费品都是基于wifi联网的设备。从商家那里达到消费者手中之后,简单开机使用无法体现其全部价值,还是需要经过消费者给设备配网的过程,把设备从信息孤岛接入互联互通的世界。

8.5 DebuggerPresent

CheckRemoteDebuggerPresent 也是一个微软提供的反调试函数,该函数可以在本地或者远程进程中使用。函数接收两个参数进程句柄和一个指向布尔值的指针。如果指定的进程正在被调试,则函数会把指向布尔值的指针设为 TRUE,否则设为FALSE。

kettle从入门到精通 第七十一课 ETL之kettle 再谈http post,轻松掌握body中传递json参数

场景: kettle中http post步骤如何发送http请求且传递body参数? 解决方案: http post步骤中直接设置Request entity field字段即可。 1、手边没有现成的post接口,索性用python搭建一个简单的接口,关键代码如下(安装python环境略): fro