Java 业务开发常见错误 100 例
朱晔
贝壳金服资深架构师
52944 人已学习
新⼈⾸单¥59
登录后,你可以任选4讲全文学习
课程目录
已完结/共 48 讲
代码篇 (23讲)
Java 业务开发常见错误 100 例
15
15
1.0x
00:00/00:00
登录|注册

22 | 接口设计:系统间对话的语言,一定要统一

思考与讨论
接口处理方式
版本控制策略
响应体设计
接口设计

该思维导图由 AI 生成,仅供参考

你好,我是朱晔。今天,我要和你分享的主题是,在做接口设计时一定要确保系统之间对话的语言是统一的。
我们知道,开发一个服务的第一步就是设计接口。接口的设计需要考虑的点非常多,比如接口的命名、参数列表、包装结构体、接口粒度、版本策略、幂等性实现、同步异步处理方式等。
这其中,和接口设计相关比较重要的点有三个,分别是包装结构体、版本策略、同步异步处理方式。今天,我就通过我遇到的实际案例,和你一起看看因为接口设计思路和调用方理解不一致所导致的问题,以及相关的实践经验。

接口的响应要明确表示接口的处理结果

我曾遇到过一个处理收单的收单中心项目,下单接口返回的响应体中,包含了 success、code、info、message 等属性,以及二级嵌套对象 data 结构体。在对项目进行重构的时候,我们发现真的是无从入手,接口缺少文档,代码一有改动就出错。
有时候,下单操作的响应结果是这样的:success 是 true、message 是 OK,貌似代表下单成功了;但 info 里却提示订单存在风险,code 是一个 5001 的错误码,data 中能看到订单状态是 Cancelled,订单 ID 是 -1,好像又说明没有下单成功。
{
"success": true,
"code": 5001,
"info": "Risk order detected",
"message": "OK",
"data": {
"orderStatus": "Cancelled",
"orderId": -1
}
}
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
  • 深入了解
  • 翻译
    • 英语
    • 中文简体
    • 中文繁体
    • 法语
    • 德语
    • 日语
    • 韩语
    • 俄语
    • 西班牙语
    • 阿拉伯语
  • 解释
  • 总结

接口设计在系统间对话中扮演着关键角色,确保对话的语言统一至关重要。本文深入讨论了接口设计的多个关键点,包括接口的命名、参数列表、包装结构体、接口粒度、版本策略、幂等性实现、同步异步处理方式等。特别强调了包装结构体、版本策略、同步异步处理方式在设计中的重要性。通过实际案例展示了由于接口设计思路和调用方理解不一致所导致的问题,并分享了相关的实践经验。文章提出了对外隐藏内部实现和明确每个字段的含义、以及客户端的处理方式的设计原则。通过调整返回结构体和明确接口的设计逻辑,使得接口设计更加合理。最后,分享了一个小技巧,通过框架自动完成包装API响应体的工作,以及定义一个@RestControllerAdvice来完成自动包装响应体的工作。这篇文章对于读者快速了解接口设计的关键要点以及避免常见问题提供了有益的技术指导。文章中还介绍了@NoAPIResponse自定义注解的使用方法,以及如何在ResponseBodyAdvice中排除标记有这个注解的方法或类的自动响应体包装。这些技术细节和实践经验为读者提供了宝贵的指导,有助于他们更好地理解接口设计的重要性和实际应用。文章内容丰富,涵盖了接口设计的多个关键点,通过实际案例展示了问题及解决方案,对于读者快速了解接口设计的关键要点以及避免常见问题提供了有益的技术指导。

仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《Java 业务开发常见错误 100 例》
新⼈⾸单¥59
立即购买
登录 后留言

全部留言(25)

  • 最新
  • 精选
  • 👽
    第一个问题我的解决是控制为更少的错误代码 调用数据库是一种,调用服务失败是一种,业务层错误是一种 返回到客户端的时候,客户端之判断错误类型是哪一类,从而做相应的处理。并不告知客户端详细的错误内容。详细的错误内容应该由后端工程师来把控。

    作者回复: 服务端需要做错误码归类收敛,特别是应该转换下游服务多少异常,否则客户端会不知所措。我们之前尝试过服务端驱动的方式,让服务端告知客户端如何处理,说白了客户端只需要照做即可,不需要感知错误码的含义,即便客户端显示错误码也只是用于排错,下面是相关介绍: 说白了这种模式,就是在API的返回结果中包含驱动客户端去怎么做的信息,两个层次: 1、交互驱动:比如包含actionType和actionInfo,actionType可以是toast、alert、redirectView、redirectWebView等,actionInfo就是toast的信息、alert的信息、redirect的URL等。由服务端来明确客户端在请求API后的交互行为的好处是: 灵活:在紧急的时候还可以通过redirect方式进行救急,比如遇到特殊情况需要紧急进行逻辑修改可以直接在不发版的情况下切换到H5实现,甚至我们可以提供后台让产品或运营来配置交互的方式和信息 统一:有的时候会遇到不同的客户端,iOS、Android、前端对于交互的实现不统一的情况,如果API结果可以规定这部分内容可以彻底避免这个问题 2、行为驱动:更深一层的服务端驱动,可以实现一套API作为入口,让客户端进行调用,然后通过约定一套DSL告知客户端应该呈现什么,干什么。 之前有两个这样的项目采用了类似的API设计方式: 贷款审核:我们知道贷款的信用审核逻辑往往会变动比较大,还涉及到客户端的一些授权(比如运营商爬虫),而且App的发布更新往往比较困难(苹果App Store以及安卓各大应用商店的审核问题)。如果采用服务端驱动的架构来告知客户端接下去应该呈现什么界面做什么,那么会有很大的灵活性。 客户端爬虫:我们知道如果采用服务端做爬虫很多时候因为IP的问题会被封,所以需要找很多代理。某项目我们想出了客户端共享代理的概念,使用手机客户端来做分布式代理,由服务端驱动调度所有的客户端,那么这个时候客户端需要听从服务端的指示来做请求然后上报响应。 一般而言,对外的Web API是不会采用这种服务端驱动客户端的方式来设计API的。对于某些特殊类型的项目,我们可以考虑采用这种服务端驱动的方式来设计API,让客户端变为一个不含逻辑的执行者,执行的是UI和交互。

    2020-05-12
    2
    22
  • 梦倚栏杆
    1.第一个问题:可以参考http状态码的实现方式,一类错误以相同的数字前缀开头。我们实践的并不好(业务系统):透传上游错误码;或者是改编一下调用哪个服务哪个接口失败;理由:不管哪出了问题,都是端上的同学的先排查问题,为了节省时间,从错误信息可以方便的定位到底是哪出了问题。 2.第二个问题:可维护性怎么办。我们当前使用的是spring MVC 或者jersey框架开发接口,IDEA都有现成的插件可以直接看接口。这种方式想知道完整的接口还需要了解apiVersion实现逻辑。可能会有人说看文档,但是文档和代码的一致性怎么保证呢

    作者回复: 1. 可以开发一个独立的错误码服务,实现转码、分类、收敛逻辑,甚至可以开发后台,让产品来录入需要的错误码提示消息。阿里的Java开发手册中也有提到相关错误码的一些推荐的最佳实践。 2. 这确实是一个问题,所以框架如果做的好的话不仅仅要扩展功能部分还要打通文档,比如如果使用springdoc来什生成OpenAPI文档,那么直接把那部分生成URL的逻辑也改了

    2020-05-06
    6
    13
  • x-ray
    @APIVersion那段太牛了,翻看过SpringMVC的代码,也知道RequestMappingHandlerMapping是干什么用的。但从来没想过,可以这样玩,可以给业务代码增加生产力。

    作者回复: 哈哈

    2021-03-21
    12
  • Seven.Lin澤耿
    其实,我不是很认同用数字作为错误码,为何不用单词来做呢?就跟单元测试test1、test2一样,没什么意义,直接用类似`USER_NOT_EXIST`类似的不可以吗?

    作者回复: 引用自《阿里Java开发手册泰山版》 12.【参考】错误码尽量有利于不同文化背景的开发者进行交流与代码协作。 说明:英文单词形式的错误码不利于非英语母语国家(如阿拉伯语、希伯来语、俄罗斯语等)之间的开发 者互相协作。

    2020-05-11
    4
    11
  • //null
    自动包装外层APIResposne响应的那边有一个问题,刚好我在做的时候遇到了,如果控制器返回的是String类型,那么返回APIResponse 对象会出现转换错误,因为我们在控制器返回的是String类型 springmvc会使用 StringHttpMessageConverter 转换器,这时候会报转换错误。

    作者回复: 是的,把MappingJackson2HttpMessageConverter放在最前面即可,或者在ResponseBodyAdvice里面判断类型,特殊处理

    2020-06-05
    2
    9
  • Demon.Lee
    1. 我们有一个code的字典表,就是excel中列出来,每新增一个,就在里面加一个,前端根据这个表格在代码中实现字典表查询,然后用友好的提示展示给用户。 2. 回头补代码。 有个疑问, “特殊情况下,比如收单服务内部处理不当,或是订单服务出现了额外的状态,虽然 success 为 true,但订单实际状态不是 Created,这时可以给予友好的错误提示。” -------我们没有这么干,我一时也有点接受不了,只要有错误,success肯定是false,所以想问问老师,有具体的案例可以分享下么,谢谢。其他小伙伴,你们呢,也是这么干么。

    作者回复: 特殊情况下,比如收单服务内部处理不当,或是订单服务出现了额外的状态,虽然 success 为 true,但订单实际状态不是 Created,这时可以给予友好的错误提示。》》这段我是指客户端的处理逻辑,客户端需要考虑到各种服务端响应的可能。

    2020-05-05
    2
    4
  • 昵称而已,何必执着
    @APIVersion 这种的控制版本,swagger怎么办?

    作者回复: swagger可以同步修改

    2020-08-03
    2
  • Geek_c5e36a
    “虽然说收单服务调用订单服务进行真正的下单操作,但是直接接口其实是收单服务提供的,收单服务不应该“直接”暴露其背后订单服务的状态码、错误描述。”,老师,这里我有个疑问,如果是作为一种中台系统,如果不把下游的错误描述返回给上游,这样的话,每次上游出问题都得找你查状态码,错误描述,然后在找下游系统解决,这样会给系统运维带来很大的压力吧?

    作者回复: 中台系统也应该尽量抽象&屏蔽背后具体的服务,错误码可以提供统一的后台查询

    2021-07-11
    1
  • 阿清
    大腿,请教一个问题。系统是一个单体SSH项目,有一个业务场景,比如:系统中有一个用户录入或修改单据操作,用户录入或修改完成后,不仅要保存在本系统中,同时还有调用另外一个系统接口,把数据传给他们。问题是如何做到类似事务统一?

    作者回复: 本地事务+MQ事务性消息/或事务性MQ作为整体事务,由MQ确保数据最终可以发给另一个接口 当然也可以本地保存后比较粗暴通过状态位实现远程接口调用的补偿,通过Job补偿失败的接口调用

    2021-05-11
    2
    1
  • ifelse
    很实用

    作者回复: 感谢

    2021-05-06
    1
收起评论
显示
设置
留言
25
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部