文章目录
明确的接口定义和文档化
接口的明确定义和完善的文档能够减少沟通成本,避免误用。文档化还可以方便后续维护和扩展。
使用RESTful设计规范
遵循RESTful设计风格,使得接口更具一致性和可读性,并便于理解和使用。
分页和过滤
对于返回大量数据的接口,使用分页和过滤以减少数据传输量和提高响应速度。
合理使用缓存
在高并发的后端系统中,合理使用缓存可以显著提升性能,减轻数据库的压力,并缩短接口的响应时间。缓存的核心思想是将一些计算量大、访问频繁的数据暂时存储在内存中(如Redis、Memcached等),当下次请求相同数据时,可以直接从缓存中获取,而不需要再次访问数据库或执行复杂的计算。
限流与熔断机制
限流与熔断机制旨在防止系统过载,保护服务稳定性。限流控制请求频率,避免瞬间高并发冲击;熔断则在服务不稳定时主动停止请求,防止连锁故障,并在服务恢复后逐步恢复正常请求。
安全性设计
确保接口的安全性,如身份认证、权限校验和数据加密,避免数据泄露和未授权访问。
异步处理与后台任务
对于需要耗时较长的操作,可以通过异步处理或后台任务方式提高接口的响应速度。
接口参数校验(入参和出参)
接口入参和出参都需要进行校验, ① 例如入参是否不能为空,入参数据长度,入参是否符合预期规则,很多bug由于未做参数校验导致,对于可能改变的参数建议设计为对象类型;② 对于返回值,当返回值为空时是否返回为空串、空对象、空数组,需要与前端约定好。
接口扩展性考虑
在后端接口设计中,扩展性是非常重要的考虑因素。设计良好的接口应该能够适应业务需求的变化,易于扩展而不需要对现有系统做出大规模修改。
核心接口,线程池隔离
登录接口、首页数据接口、转账提现接口等,都可能使用到线程池,某些普通接口也会使用线程池,如果不做线程池隔离,普通接口出bug线程池打满,会导致登录等主要业务受到影响。
关键接口,日志打印
关键业务代码,需要打印日志进行保驾护航,在入参和出参位置或者其他关键位置,良好的日志打印具有如下好处:① 方便排查定位线上问题,划清问题责任;② 生产环境不能直接debug,必须依靠日志查问题和具体异常。
接口功能单一性原则
单一性是指接口做的事情比较单一、专一。比如一个登陆接口,它做的事情就只是校验账户名密码,然后返回登陆成功以及userId即可。但是如果你为了减少接口交互,把一些注册、一些配置查询等全放到登陆接口,就不太妥。其实这也是微服务一些思想,接口的功能单一、明确。比如订单服务、积分、商品信息相关的接口都是划分开的。将来拆分微服务的话,是不是就比较简便啦。
接口查询优化,串行改为并行
在设计一个APP首页接口时,如果它需要从多个不同的数据源获取信息(如用户信息、banner信息、弹窗信息等),通常有两种常见的调用方式:串行调用和并行调用。为了提高接口的响应速度,优化用户体验,采用并行调用是更优的选择,尤其是在这些调用之间没有依赖关系时。
并行调用允许多个请求同时执行,不必等待彼此完成。Java中的CompletableFuture可以很方便地实现这一点。
确保接口兼容性的策略
在修改老接口时,接口的兼容性是一个非常重要的考虑因素,特别是在系统已经上线并且被多个客户端使用的情况下。以下是一些确保接口兼容性的策略和最佳实践。
- 向后兼容性
定义:向后兼容性指的是旧版本的客户端仍然可以正常使用新版本的接口,而不需要任何修改。
策略:
保持现有字段不变:不要随意修改或删除现有的字段或参数,这样可以保证旧客户端仍然能按预期工作。
新增字段:如果需要扩展数据模型,可以新增字段或参数,但这些新增内容应该是可选的。旧客户端可以忽略这些新字段,而新客户端则可以利用它们。
保持返回类型不变:尽量保持返回的JSON或XML结构不变,尤其是数据类型、字段名等。如果必须改变,确保新老结构兼容,或提供降级逻辑。 - 版本管理
定义:当新功能或重大修改不可避免地会破坏现有客户端时,应该采用接口版本管理策略。
策略:
路径版本化:在URL路径中添加版本号,例如/api/v1/user和/api/v2/user。这种方式直观,客户端明确知道调用的是哪个版本的接口。
请求头版本化:通过HTTP请求头指定版本号,例如Accept: application/vnd.company.v1+json。这种方式不会影响URL的结构。
API网关:使用API网关进行版本管理和路由,能够更灵活地处理不同版本的接口。
调用第三方接口要考虑异常和超时处理
在调用第三方接口时,异常和超时处理是至关重要的。这些问题如果处理不当,会导致应用程序的不稳定,甚至崩溃。为了确保系统的健壮性和用户体验的稳定性,以下是一些关键的考虑和处理策略。
重试机制:在遇到网络异常时,可以尝试进行重试,通常是几次有限次数的重试。例如,可以使用指数退避算法来增加重试间隔时间,避免因频繁重试造成更多的问题。
兜底方案:如果多次重试后仍然失败,返回默认值或使用缓存中的数据,确保系统能够继续工作。
降级处理:当第三方服务异常时,提供降级服务。例如,返回一个友好的错误信息或使用本地的备用数据。
告警通知:当出现服务异常时,触发告警通知运维团队,以便快速响应。
调用第三方接口时,必须设定合理的超时时间,以避免长时间等待。
超时重试:在设定的超时时间内如果请求未完成,可以尝试重试,通常可以设置有限次重试,避免无限循环。
当某个第三方接口频繁出现异常或超时时,可以采用熔断机制,暂时停止对该接口的调用,避免对系统产生更大的影响。
日志记录:详细记录每次第三方接口调用的请求和响应信息,特别是在出现异常和超时时,确保可以进行后续的排查。
监控与报警:设置接口调用的监控指标,如成功率、平均响应时间等,当某些指标超过阈值时,立即报警通知相关人员。
接口实现过程中,注意大文件、大事务、大对象
• 读取大文件时,不要Files.readAllBytes直接读取到内存,这样会OOM的,建议使用BufferedReader一行一行来。
• 大事务可能导致死锁、回滚时间长、主从延迟等问题,开发中尽量避免大事务。
• 注意一些大对象的使用,因为大对象是直接进入老年代的,可能会触发fullGC
仔细检查代码避免出现粗心的空指针异常
空指针异常(NullPointerException)是 Java 开发中常见的错误之一。它通常发生在尝试对一个 null 对象引用进行操作时。
使用工具如 IntelliJ IDEA 的代码分析功能、SonarQube、FindBugs、Checkstyle 等,这些工具可以帮助检测可能的空指针异常问题。
在方法和构造函数中,进行参数 null 检查,抛出适当的异常。
对可能返回 null 的方法结果进行检查或处理。
对可能的参数值都进行null检查。
考虑是否存在事务失效的问题场景
• 方法的访问权限必须是public,其他private等权限,事务失效
• 方法被定义成了final的,这样会导致事务失效。
• 在同一个类中的方法直接内部调用,会导致事务失效。
• 一个方法如果没交给spring管理,就不会生成spring事务。
• 多线程调用,两个方法不在同一个线程中,获取到的数据库连接不一样的。
• 表的存储引擎不支持事务
• 如果自己try...catch误吞了异常,事务失效。
• 错误的传播特性