原来阿里华为等大厂都是这么设计微服务接口的!(下)

本文涉及的产品
云原生网关 MSE Higress,422元/月
服务治理 MSE Sentinel/OpenSergo,Agent数量 不受限
注册配置 MSE Nacos/ZooKeeper,118元/月
简介: 第一,针对响应体的设计混乱、响应结果的不明确问题,服务端需要明确响应体每一个字段的意义,以一致的方式进行处理,并确保不透传下游服务的错误。 第二,针对接口版本控制问题,主要就是在开发接口之前明确版本控制策略,以及尽量使用统一的版本控制策略两方面。 第三,针对接口的处理方式,我认为需要明确要么是同步要么是异步。如果API列表中既有同步接口也有异步接口,那么最好直接在接口名中明确。

版本实现方式

某项目需针对商品、商店和用户实现REST接口。

虽然大家约定通过URL Path方式实现API版本控制,但实现不一:

@GetMapping("/api/item/v1")
@GetMapping("/api/v1/shop")
@GetMapping("/v1/api/merchant")

显然,商品、商店和商户的接口开发没有按一致URL格式实现接口的版本控制,这时/api/v1/user和/api/user/v1,这到底是一个接口还是两个?


相比于在每个接口的URL Path中设置版本号,更理想的方式是在框架层面实现统一。使用Spring按下面方式自定义RequestMappingHandlerMapping。


首先,创建一个注解来定义接口的版本。@APIVersion自定义注解应用于方法或Controller上:

@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface APIVersion {
    String[] value();
}

然后,定义一个APIVersionHandlerMapping类继承RequestMappingHandlerMapping。


RequestMappingHandlerMapping的作用,是根据类或方法上的**@RequestMapping来生成RequestMappingInfo**的实例。


重写registerHandlerMethod方法的实现,从**@APIVersion**自定义注解中读取版本信息,拼接上原有的、不带版本号的URL Pattern,构成新的RequestMappingInfo,来通过注解的方式为接口增加基于URL的版本号:

image.png

要通过实现WebMvcRegistrations接口,来生效自定义的APIVersionHandlerMapping:

image.png

这样,就实现了在Controller上或接口方法上通过注解,来实现统一的Pattern进行版本号控制:

@GetMapping(value = "/api/user")
@APIVersion("v4")
public int right4() {
    return 4;
}

使用框架来明确API版本的指定策略,不仅实现了标准化,更实现了强制的API版本控制。对上面代码略做修改,我们就可以实现不设置@APIVersion接口就给予报错提示。

接口明确同步/异步

某文件上传服务,上传接口特慢,因为该接口在内部需两步操作

  • 首先上传原图
  • 压缩后上传缩略图

如果每一步都耗时5s,则该接口返回至少需10s。

于是把接口改为异步,每步操作都限定超时时间,即分别把上传原文件和上传缩略图的操作提交到线程池,然后等待一定时间。

上传接口的请求和响应比较简单,传入二进制文件,传出原文件和缩略图下载地址。

这种实现ok吗?

接口命名虽然是同步上传操作,但其内部通过线程池进行异步上传,并因为设置了较短超时所以接口整体响应挺快。但一旦遇到超时,接口就不能返回完整的数据,不是无法拿到原文件下载地址,就是无法拿到缩略图下载地址,接口的行为变得不可预测。

所以,这种优化接口响应速度的方式并不可取,更合理的方式是,让上传接口要么完全同步处理,要么完全异步处理:


  • 同步处理,接口一定是同步上传原文件和缩略图的,调用方可自己选择调用超时,如果来得及可以一直等到上传完成,如果等不及可以结束等待,下一次重试
  • 异步处理,接口是两段式,上传接口本身只是返回一个任务ID,然后异步做上传操作,上传接口响应很快,客户端需要之后再拿着任务ID调用任务查询接口查询上传的文件URL


同步上传接口的实现,超时选择留给客户端:

image.png

接口的入参和出参DTO的命名,推荐使用接口名+Request和Response后缀

异步的上传文件接口不再返回文件URL,而是返回一个任务ID:

@Data
public class AsyncUploadRequest {
    private byte[] file;
}
@Data
public class AsyncUploadResponse {
    private String taskId;
}

把上传任务提交到线程池处理,但不会同步等待任务完成,而是完成后把结果写入一个HashMap,任务查询接口通过查询这个HashMap获得文件URL:

image.png

文件上传查询接口则以任务ID作为入参,返回两个文件的下载地址,因为文件上传查询接口是同步的,所以直接命名为syncQueryUploadTask:

image.png

改造后的FileService提供很明确的:

  • 同步上传接口syncUpload
  • 异步上传接口asyncUpload,搭配syncQueryUploadTask查询上传结果

使用方可以根据业务性质选择合适的方法:

  • 如果是后端批处理使用,那么可使用同步上传,多等待一些时间问题不大
  • 如果是面向用户的接口,那么接口响应时间不宜过长,可以调用异步上传接口,然后定时轮询上传结果,拿到结果再显示

总结

第一,针对响应体的设计混乱、响应结果的不明确问题,服务端需要明确响应体每一个字段的意义,以一致的方式进行处理,并确保不透传下游服务的错误。

第二,针对接口版本控制问题,主要就是在开发接口之前明确版本控制策略,以及尽量使用统一的版本控制策略两方面。


第三,针对接口的处理方式,我认为需要明确要么是同步要么是异步。如果API列表中既有同步接口也有异步接口,那么最好直接在接口名中明确。


一个良好的接口文档不仅需说明如何调用接口,更需要补充接口使用的最佳实践以及接口的SLA标准。

太多接口文档只给参数定义,但诸如幂等性、同步异步、缓存策略等看似内部实现相关的一些设计,其实也会影响调用方对接口的使用策略,最好也体现在接口文档。


对于服务端出错时是否返回200响应码,从RESTful设计原则看,应该尽量利用HTTP状态码表达错误,但现实都不是这么绝对。


如果认为HTTP 状态码是协议层面的契约,那当这个错误已经不涉及HTTP协议时(即服务端已收到请求进入服务端业务处理后产生的错误),不一定需要硬套协议本身的错误码。

但涉及非法URL、非法参数、没有权限等无法处理请求的情况,还是应该使用正确的响应码来应对。


目录
相关文章
|
5月前
|
Java API 微服务
【Spring Boot系列】通过OpenAPI规范构建微服务服务接口
【4月更文挑战第5天】通过OpenAPI接口构建Spring Boot服务RestAPI接口
215 0
|
5月前
|
微服务
jeecg微服务项目调用接口报错Token验证失效的解决方法
jeecg微服务项目调用接口报错Token验证失效的解决方法
|
5月前
|
消息中间件 分布式计算 中间件
秀出天际!阿里甩出的988页分布式微服务架构进阶神仙手册我粉了
秀出天际!阿里甩出的988页分布式微服务架构进阶神仙手册我粉了
|
5月前
|
Java 数据库 索引
最强阿里及大厂350道面试大全:框架+数据库+并发+开源+微服务
无论是对于刚入行工作还是已经工作几年的java开发者来说,面试求职始终是你需要直面的一件事情。首先梳理自己的知识体系,针对性准备,会有事半功倍的效果。我们往往会把重点放在技术上,而忽略了人事部分,实际上人事面试也会影响到最终的结果,把每一个环节做好,最终的结果自然不会差。
|
5月前
|
Java Docker 微服务
阿里P8携手腾讯T4谈微服务架构实战:深入浅出Cloud+boot+Docker
微服务”架构在这几年被广泛传播,变得非常火热,以至于关于微服务架构相关的开源框架和工具都变得越来越活跃,比如: Netflix OSS. Dubbo. Apache Thrift等。Spring Cloud也因为Spring社区在企业应用领域的广泛知名度和强大影响力,受到了广大架构师与开发者的高度关注。
|
10月前
|
存储 弹性计算 运维
傻掉!看华为技术专家的500页微服务架构笔记,感觉我格局太小
未来10年是各行各业数字化转型的关键10年。数字化转型将帮助企业打破原有IT系统的烟囱状布局,解决IT应用数据孤岛问题,实现数据集中管理共享,从而为企业降低成本、提高运营效率、加快产品创新提供平台和技术保证,使企业在市场竞争中获得优势。
|
5月前
|
Dubbo 应用服务中间件 Docker
阿里P8架构师谈微服务架构:Dubbo+Docker+SpringBoot+Cloud
什么是微服务架构呢?简单说就是将一个完整的应用(单体应用) 按照一定的拆分规则(后文讲述)拆分成多个不同的服务,每个服务都能独立地进行开发、部署、扩展。服务于服务之间通过注入RESTful api或其他方式调用。
|
5月前
|
消息中间件 前端开发 架构师
华为架构师复盘2024最全2340页面试题jvm+spring+redis+MQ+微服务
包括 Java 集合、JVM、多线程、并发编程、设计模式、Spring全家桶、Java、MyBatis、ZooKeeper、Dubbo、Elasticsearch、Memcached、MongoDB、Redis、MySQL、RabbitMQ、Kafka、Linux、Netty、Tomcat、Python、HTML、CSS、Vue、React、JavaScript、Android 大数据、阿里巴巴等大厂面试题等、等技术栈!
|
5月前
|
负载均衡 Dubbo 应用服务中间件
阿里微服务架构到底多牛逼:深入解析Apache Dubbo与实战
在Apache Dubbo (以下简称Dubbo)重新开源之前,Dubbo已经被很多公司广泛用于生产环境并获得了良好的反馈,很多公司内部也会建立私有分支自己维护,其中Dubbox 就是基于Dubbo分支进行扩展并二次维护的。重新开源后,社区维护的Dubbo版本进行了大量“bug fix" .和特性支持,收到了大量Dubbo用户的支持和参与。编写本书的想法是在开源后提出来的,因此本书取名《深入理解Apache Dubbo与实战》。
|
22天前
|
安全 应用服务中间件 API
微服务分布式系统架构之zookeeper与dubbo-2
微服务分布式系统架构之zookeeper与dubbo-2