什么?你设计接口什么都不考虑?

news2024/11/13 14:41:47

 

如果让你设计一个接口,你会考虑哪些问题?

1.接口参数校验

接口的入参和返回值都需要进行校验。

  • 入参是否不能为空,入参的长度限制是多少,入参的格式限制,如邮箱格式限制

  • 返回值是否为空,如果为空的时候是否返回默认值,这个默认值需要和前端协商

2.接口扩展性

举个例子,比如用户在进行某些操作之后,后端需要进行消息推送,那么是直接针对这个业务流程来开发一个专门为这个业务流程服务的消息推送功能呢?还是说将消息推送整合为一个通用的接口,其他流程都可以进行调用,并非针对特定业务。

这个场景可能光靠说不是很能理解,大家想想策略工厂设计模式,是不是可以根据不同的策略,来选择不同的实现方式呢?再结合上面的这个例子,是否对扩展性有了进一步的理解呢?

3.接口幂等设计

什么是幂等呢?幂等是指多次调用接口不会改变业务状态,可以保证重复调用的结果和单次调用的结果一致。

举个例子,在购物商场里面你用手机下单,要买某个商品,你需要去支付,然后你点击了支付,但是因为网速问题,始终没有跳转到支付界面,于是你又连点了几次支付,那在没有做接口幂等的时候,是不是你点击了多少次支付,我们就需要执行多少次支付操作?

所以接口幂等到的是什么?防止用户多次调用同一个接口

  • 对于查询和删除类型的接口,不论调用多少次,都是不会产生错误的业务逻辑和数据的,因此无需幂等处理

  • 对于新增和修改,例如转账等操作,重复提交就会导致多次转账,这是很严重的,影响业务的接口需要做接口幂等的处理,跟前端约定好一个固定的token接口,先通过用户的id获取全局的token,写入到Redis缓存,请求时带上Token,后端做处理

4.关键接口日志打印

关键的业务代码,是需要打印日志进行监测的,在入参和返回值或者如catch代码块中的位置进行日志打印

  • 方便排查和定位线上问题,划清责任

  • 生产环境是没有办法进行debug的,必须依靠日志查问题,看看到底是出现了什么异常情况

5.核心接口要进行线程池隔离

分类查询啊,首页数据等接口,都有可能使用到线程池,某些普通接口也可能会使用到线程池,如果不做线程池隔离,万一普通接口出现bug把线程池打满了,会导致你的主业务受到影响

6.第三方接口异常重试

如果有场景出现调用第三方接口,或者分布式远程服务的话,需要考虑的问题

  • 异常处理

    比如你在调用别人提供的接口的时候,如果出现异常了,是要进行重试还是直接就是当做失败

  • 请求超时

    有时候如果对方请求迟迟无响应,难道就一直等着吗?肯定不是这样的,需要设法预估对方接口响应时间,设置一个超时断开的机制,以保护接口,提高接口的可用性,举个例子,你去调用别人对外提供的一个接口,然后你去发http请求,始终响应不回来,此时你又没设置超时机制,最后响应方进程假死,请求一直占着线程不释放,拖垮线程池。

  • 重试机制

    如果调用对外的接口失败了或者超时了,是否需要重新尝试调用呢?还是失败了就直接返回失败的数据?

7.接口是否需要采用异步处理

举个例子,比如你实现一个用户注册的接口。用户注册成功时,发个邮件或者短信去通知用户。这个邮件或者发短信,就更适合异步处理。总不能一个通知类的失败,导致注册失败吧。那我们如何进行异步操作呢?可以使用消息队列,就是用户注册成功后,生产者产生一个注册成功的消息,消费者拉到注册成功的消息,就发送通知。

8.接口查询优化,串行优化为并行

假设我们要开发一个网站的首页,我们设计了一个首页数据查询的接口,这个接口需要查用户信息,需要查头部信息,需要查新闻信息

等等之类的,最简单的就是一个一个接口串行调用,那要是想要提高性能,那就采取并行调用的方式,同时查询,而不是阻塞

可以使用CompletableFuture(推荐)或者FutureTask(不推荐)

  1.         Map<Long, List<SubjectLabelBO>> map = new HashMap<>();

  2.         List<CompletableFuture<Map<Long, List<SubjectLabelBO>>>> completableFutureList = 

  3.         categoryBOList.stream().map(category ->

  4.                 CompletableFuture.supplyAsync(() -> getLabelBOList(category), labelThreadPool)

  5.         ).collect(Collectors.toList());

  6.         completableFutureList.forEach(future -> {

  7.             try {

  8.                 Map<Long, List<SubjectLabelBO>> resultMap = future.get(); //这里会阻塞

  9.                 map.putAll(resultMap);

  10.             } catch (Exception e) {

  11.                 e.printStackTrace();

  12.             }

  13.         });

  14.         public Map<Long, List<SubjectLabelBO>> getLabelBOList(SubjectCategoryBO category) {...}

9.高频接口注意限流

自定义注解 + AOP

  1. @Target(ElementType.METHOD)

  2. @Retention(RetentionPolicy.RUNTIME)

  3. public @interface RateLimiter {

  4.     int value() default 1;

  5.     int durationInSeconds() default 1;

  6. }

  7. @Aspect

  8. @Component

  9. public class RateLimiterAspect {

  10.     private final ConcurrentHashMap<String, RateLimiter> rateLimiters = new ConcurrentHashMap<>();

  11.     @Pointcut("@annotation(RateLimiter)")

  12.     public void rateLimiterPointcut(RateLimiter rateLimiterAnnotation) {

  13.     }

  14.     @Around("rateLimiterPointcut(rateLimiterAnnotation)")

  15.     public Object around(ProceedingJoinPoint joinPoint, RateLimiter rateLimiterAnnotation) throws Throwable {

  16.         int permits = rateLimiterAnnotation.value();

  17.         int durationInSeconds = rateLimiterAnnotation.durationInSeconds();

  18.         // 使用方法签名作为 RateLimiter 的 key

  19.         String key = joinPoint.getSignature().toLongString();

  20.         com.google.common.util.concurrent.RateLimiter rateLimiter = rateLimiters.computeIfAbsent(key, k -> com.google.common.util.concurrent.RateLimiter.create((double) permits / durationInSeconds));

  21.         // 尝试获取令牌,如果获取到则执行方法,否则抛出异常

  22.         if (rateLimiter.tryAcquire()) {

  23.             return joinPoint.proceed();

  24.         } else {

  25.             throw new RuntimeException("Rate limit exceeded.");

  26.         }

  27.     }

  28. }

  29. @RestController

  30. public class ApiController {

  31.     @GetMapping("/api/limited")

  32.     @RateLimiter(value = 10, durationInSeconds = 60) //限制为每分钟 10 次请求

  33.     public String limitedEndpoint() {

  34.         return "This API has a rate limit of 10 requests per minute.";

  35.     }

  36.     @GetMapping("/api/unlimited")

  37.     public String unlimitedEndpoint() {

  38.         return "This API has no rate limit.";

  39.     }

  40. }

10.保障接口安全

配置黑白名单,用Bloom过滤器实现黑白名单的配置

具体代码不贴出来了,大家可以去看看布隆过滤器的具体使用

11.接口控制锁粒度

在高并发场景下,为了防止超卖等情况,我们会对共享资源进行加锁的操作来保证线程安全的问题,但是如果加锁的粒度过大,是会影响

到接口性能的。那什么是加锁粒度呢?举一个例子,你带了一封情书回家,但是不想被爸妈发现,然后你偷偷回到房间里放到一个可以锁

住的抽屉里面,而不用把房间的门锁给锁上。无论是使用synchronized加锁还是redis分布式锁,只需要在共享临界资源加锁即可,不涉

及共享资源的,就不必要加锁。

  • 锁粒度过大:

    把方法A和方法B全部进行加锁,但是实际上我只是想要对A加锁,这就是锁粒度过大

  1. void test(){

  2.     synchronized (this) {

  3.        B();

  4.        A();

  5.     }

  6. }

  • 缩小锁粒度

  1. void test(){

  2.        B();

  3.     synchronized (this) {

  4.        A();

  5.     }

  6. }

12.避免长事务问题

长事务期间可能伴随cpu、内存升高、严重时会导致服务端整体响应缓慢,导致在线应用无法使用

产生长事务的原因除了sql本身可能存在问题外,和应用层的事务控制逻辑也有很大的关系。

  • 如何尽可能的避免长事务问题呢?

  1. RPC远程调用不要放到事务里面

  2. 一些查询相关的操作如果可用,尽量放到事务外面

  3. 并发场景下,尽量避免使用@Transactional注解来操作事务,使用TransactionTemplate的编排式事务来灵活控制事务的范围

在原先使用@Transactional来管理事务的时候是这样的

  1. @Transactional

  2. public int createUser(User user){

  3.     //保存用户信息

  4.     userDao.save(user);

  5.     passCertDao.updateFlag(user.getPassId());

  6.     // 该方法为远程RPC接口

  7.     sendEmailRpc(user.getEmail());

  8.     return user.getUserId();

  9. }

使用TransactionTemplat进行编排式事务

  1. @Resource

  2. private TransactionTemplate transactionTemplate;

  3. public int createUser(User user){

  4.     transactionTemplate.execute(transactionStatus -> {

  5.       try {

  6.          userDao.save(user);

  7.          passCertDao.updateFlag(user.getPassId());

  8.       } catch (Exception e) {

  9.          // 异常手动设置回滚

  10.          transactionStatus.setRollbackOnly();

  11.       }

  12.       return true;

  13.     });

  14.     // 该方法为远程RPC接口

  15.     sendEmailRpc(user.getEmail());

  16.     return user.getUserId();

  17. }

总结:

感谢每一个认真阅读我文章的人!!!

作为一位过来人也是希望大家少走一些弯路,如果你不想再体验一次学习时找不到资料,没人解答问题,坚持几天便放弃的感受的话,在这里我给大家分享一些自动化测试的学习资源,希望能给你前进的路上带来帮助。

软件测试面试文档

我们学习必然是为了找到高薪的工作,下面这些面试题是来自阿里、腾讯、字节等一线互联网大厂最新的面试资料,并且有字节大佬给出了权威的解答,刷完这一套面试资料相信大家都能找到满意的工作。

 

          视频文档获取方式:
这份文档和视频资料,对于想从事【软件测试】的朋友来说应该是最全面最完整的备战仓库,这个仓库也陪伴我走过了最艰难的路程,希望也能帮助到你!以上均可以分享,点下方小卡片即可自行领取。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1680223.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

代码随想录算法训练营第二十九天 | 39. 组合总和、40.组合总和II、131.分割回文串

39. 组合总和 题目链接/文章讲解&#xff1a; 代码随想录 视频讲解&#xff1a;带你学透回溯算法-组合总和&#xff08;对应「leetcode」力扣题目&#xff1a;39.组合总和&#xff09;| 回溯法精讲&#xff01;_哔哩哔哩_bilibili 解题思路 这里和组合不同的是元素可以重复选取…

2024 Google I/O大会:全方位解读最新AI技术和产品

引言&#xff1a; 2024年的Google I/O大会如期举行&#xff0c;作为技术圈的年度盛事之一&#xff0c;谷歌展示了其在人工智能领域的最新进展。本次大会尤其引人注目&#xff0c;因为它紧随着OpenAI昨天发布GPT-4o的脚步。让我们详细解析Google此次公布的各项新技术和产品&…

【C语言】6.C语言VS实用调试技巧(1)

文章目录 1.什么是 bug2.什么是调试&#xff08;debug&#xff09;&#xff1f;3.Debug 和 Release4.VS调试快捷键4.1 环境准备4.2 调试快捷键 5.监视和内存观察5.1 监视5.2 内存 1.什么是 bug bug现在一般是指在电脑系统或程序中&#xff0c;隐藏着的一些未被发现的缺陷或问题…

计算机系列之排序算法

20、排序算法 1、直接插入排序&#xff08;这里以从小到大排序为例&#xff09; ◆要注意的是&#xff0c;前提条件是前i-1个元素是有序的&#xff0c;第i个元素依次从第i-1个元素往前比较&#xff0c;直到找到一个比第i个元素值小的元素&#xff0c;而后插入&#xff0c;插入…

战网国际服怎么下载 暴雪战网一键下载安装图文教程

战网国际版&#xff0c;或称为Battle.net全球版&#xff0c;是暴雪娱乐构建的一项跨越国界的综合游戏交流平台&#xff0c;它无视地理限制&#xff0c;旨在服务全球每一个角落的游戏爱好者。不同于地区专属版本&#xff0c;国际版为玩家开启了一扇无门槛的大门&#xff0c;让每…

使用virtualbox和vagrant搭建centos环境报错问题解决

启动提示下面的异常&#xff1a; Timed out while waiting for the machine to boot. This means that Vagrant was unable to communicate with the guest machine within the configured ("config.vm.boot_timeout" value) time period.If you look above, you sh…

多区域OSPF路由配置

一、基础配置 1.搭建实验拓扑图 2.实验编址 具体如何配置可以看这一篇详细的博文&#xff1a;单区域OSPF实验-CSDN博客 3.分别检查六个路由器的配置&#xff1a; 使用命令display ip interface brief R1的配置 其他大家可以调出来&#xff0c;再与实验拓扑图进行比对&#…

广告小白必看|谷歌Google Ads被封禁原因是什么,如何防范?

跨境出海业务少不了需要做Google Ads推广业务&#xff1b;其中让投手们闻风丧胆的消息就是帐户被暂停。当 Google 检测到任何违反其政策且可能损害用户在线体验的行为时&#xff0c;就会发生这种情况。那么如何在做广告推广的同时&#xff0c;保证账号不被封禁呢&#xff1f;看…

Linux:文件、fd

Linux:文件、fd 前言一、C语言中常见打开文件的函数接口二、打开文件的系统调用接口三、文件描述符fd四、为何Linux下一切皆文件 前言 文件 内容 属性 所有对文件的操作本质上就分为&#xff1a;对内容的修改和对属性的修改。  内容是数据&#xff0c;属性也是数据。所以存…

Jmeter(四十一) - 从入门到精通进阶篇 - Jmeter配置文件的刨根问底 - 下篇(详解教程)

宏哥微信粉丝群&#xff1a;https://bbs.csdn.net/topics/618423372 有兴趣的可以扫码加入 1.简介 为什么宏哥要对Jmeter的配置文件进行一下讲解了&#xff0c;因为有的童鞋或者小伙伴在测试中遇到一些需要修改配置文件的问题不是很清楚也不是很懂&#xff0c;就算修改了也是…

基于51单片机的自动浇花器电路

一、系统概述 自动浇水灌溉系统设计方案&#xff0c;以AT89C51单片机为控制核心&#xff0c;采用模块化的设计方法。 组成部分为&#xff1a;5V供电模块、土壤湿度传感器模块、ADC0832模数转换模块、水泵控制模块、按键输入模块、LCD显示模块和声光报警模块&#xff0c;结构如…

Gradio 案例——将 dicom 文件转为 nii文件

文章目录 Gradio 案例——将 dicom 文件转为 nii文件界面截图依赖安装项目目录结构代码 Gradio 案例——将 dicom 文件转为 nii文件 利用 SimpleITK 库&#xff0c;将 dicom 文件转为 nii文件更完整、丰富的示例项目见 GitHub - AlionSSS/dcm2niix-webui: The web UI for dcm2…

利用MMDetection进行模型微调和权重初始化

目录 模型微调修改第一处&#xff1a;更少的训练回合Epoch修改第二处&#xff1a;更小的学习率Learning Rate修改第三处&#xff1a;使用预训练模型 权重初始化实际使用案例init_cfg 的具体使用规则初始化器配置汇总 本文基于 MMDetection官方文档&#xff0c;对模型微调和权重…

eMMC和SD模式速率介绍

概述 在实际项目开发中我们常见的问题是有人会问,“当前项目eMMC、SD所使用模式是什么? 速率是多少?”。这些和eMMC、SD的协议中要求的,要符合协议。接下来整理几张图来介绍。 eMMC 模式介绍 一般情况下我们项目中都是会支持到HS400 8bit 1.8V,最大时钟频率为200MHZ,通…

ESP8266-01模块继电器制作手机APP远程遥控智能开关

资料下载地址&#xff1a; ESP8266-01模块继电器制作手机APP远程遥控智能开关 这是一款使用ESP8266-01模块继电器制作手机APP远程遥控智能开关&#xff0c;它能实现远程遥控、定时、倒计时控制。电路简单&#xff0c;适合新手入门制作&#xff0c;下图是用这个智能开关制作的小…

springboot项目打包部署

springboot打包的前提条件jdk必须17以后不然本地运行不来&#xff08;我用的jdk是22&#xff09; 查看自己电脑jdk版本可以参考&#xff08;完美解决Windows10下-更换JDK环境变量后&#xff0c;在cmd下执行仍java -version然出现原来版本的JDK的问题-CSDN博客&#xff09; 1、…

treejs 3D+echart实现三维旋转炫酷导航网页

treejs 3Dechart实现三维旋转炫酷导航网页https://www.bilibili.com/video/BV1SM4m1C7ki/

吴恩达深度学习笔记:优化算法 (Optimization algorithms)2.1-2.2

目录 第二门课: 改善深层神经网络&#xff1a;超参数调试、正 则 化 以 及 优 化 (Improving Deep Neural Networks:Hyperparameter tuning, Regularization and Optimization)第二周&#xff1a;优化算法 (Optimization algorithms)2.1 Mini-batch 梯度下降&#xff08;Mini-b…

07-Fortran基础--Fortran指针(Pointer)的使用

07-Fortran基础--Fortran指针Pointer的使用 0 引言1 指针&#xff08;Poionter&#xff09;的有关内容1.1 一般类型指针1.2 数组指针1.3 派生类(type)指针1.4 函数指针 2 可运行code 0 引言 Fortran是一种广泛使用的编程语言&#xff0c;特别适合科学计算和数值分析。Fortran 9…

【设计模式】JAVA Design Patterns——Abstract-document(抽象文档模式)

&#x1f50d; 目的 使用动态属性&#xff0c;并在保持类型安全的同时实现非类型化语言的灵活性。 &#x1f50d; 解释 抽象文档模式使您能够处理其他非静态属性。 此模式使用特征的概念来实现类型安全&#xff0c;并将不同类的属性分离为一组接口 真实世界例子 考虑由多个部…