接口变更常见的八种场景,一定要考虑兼容性!

1. 接口新增入参字段,并且有校验逻辑
在日常开发中,经常会遇到的需求就是,在老的接口上,新增入参,并且需要校验。

这时候兼容性如何处理呢?我举个简单点的例子:

比如一个用户注册接口,突然加一个email的字段并且不能为空,且要校验是否符合邮箱格式

其实可以升级API版本,比如创建一个新的API版本,比如/v2/api/register,在这个新版本中包含email字段,并对其进行非空校验。

如果觉得每次新增个字段和简单校验这种情况,都要升级版本号,比较复杂繁琐,则可以将新字段email设置为可选。

如果客户端传了email字段,就对它校验,不传的话,直接放过,然后可以打印一下日志。

if (StringUtils.isNotBlank(userRequest.getEmail())) {
  checkEmail(userRequest.getEmail());
}else {
  log.info("old system request,email is null,request:{}", userRequest);
}

为什么要这么做呢?

举例,如果修改了接口后,还是有老的请求,不带email字段过来,站在业务角度,就是可以正常注册,如果直接校验拦截,那就有问题~~~

2. 接口错误码调整
有时可能需要对接口的错误码进行调整。如果调整了错误码,要及时更新接口文档,并通知上下游。说明错误码调整的原因。并且要做兼容性联调测试。

比如分布式锁获取失败的错误码,一开始是423000,上游依赖这个错误码来重试的。后来做分布式锁升级优化的时候,反手把它修改为666000了。如果不通知上下游,联调测试啥的,偷偷改就不管了。那后面肯定出问题,因为上游获取锁失败,没得重试了,依赖的错误码变更了。。。

3. 接口返回值调整了
其是不管是错误码调整还是返回值调整,都是有共性的。

要按照三步曲去走:

  • 更新文档,说明修改了哪些内容
  • 通知上下游,说明原因,场景
  • 兼容性联调测试

比如接口不是联机交易,而是MQ交互的。

假如作为MQ的生产者,原来的消息体有个json格式的报文,然后在本次需求调整了内容。不及时做好这3步,消费端可能因为发版本后,消费不了这个报文(比如解析不了某个特殊返回值)。

4. 接口参数新增、或者修改了校验
如果接口,原来有个字段,比如一开始最大长度是10,然后后来产品需求优化,可以增加到20。然后觉得这个需求很简单,开开心心,花十分钟改完了,把入参校验扩大位数,把数据库的字段长度修改。

后来上线的时候,下游文件核对系统跑失败了。。。因为也会对这个字段进行最大长度是10的校验。

所以做这类型需求的时候,要修改参数校验逻辑的时候。一定要考虑:兼容性。上下游是否会有影响等等。

5. 接口删除,真的没请求访问了吗
有些时候,如果发现代码没引用,就会删掉。如果是对外接口的话,不能随手就删掉,要确认是否还有调用。

删除一个对外接口,要做这几件事:

  • 跟上游确认,是否还有调用
  • 查看监控,日志确认最近一年或者说一个月是否还有调用
  • 跟产品对齐
  • 说明接口作用,为什么要删除,是否影响等等

6. 接口内部,抽取公用方法,要考虑兼容性
在抽取公用方法的时候,要考虑兼容性,不能破坏原来的逻辑。

假设有一个订单处理系统,该系统支持多种支付方式(如信用卡支付、支付宝支付等)。每个支付方式有自己的处理逻辑,但现在需要添加日志记录和异常处理,并确保这些修改不会破坏现有的支付方式。

public class OrderProcessor {

   public void processCreditCardPayment(Order order) {
   // 信用卡支付逻辑
   System.out.println("Processing credit card payment for order: " + order.getId());
   // 假设这里有复杂的支付逻辑
   }

   public void processAlipayPayment(Order order) {
   // 支付宝支付逻辑
   System.out.println("Processing Alipay payment for order: " + order.getId());
   // 假设这里有复杂的支付逻辑
   }
}

可以抽取一个公用方法来处理日志记录和异常处理,同时保持每种支付方式的特定逻辑不变。

public class OrderProcessor {
    // 公用方法,处理日志记录和异常
    private void processPaymentWithLoggingAndExceptionHandling(Order order, Runnable paymentAction) {
        try {
            // 记录日志
            System.out.println("Starting payment process for order: " + order.getId());

            // 执行支付逻辑
            paymentAction.run();

            // 记录支付成功日志
            System.out.println("Payment for order " + order.getId() + " was successful.");
        } catch (Exception e) {
            // 记录支付失败日志
            System.err.println("Payment for order " + order.getId() + " failed: " + e.getMessage());
            // 这里可以添加更多的错误处理逻辑,如重试机制或通知相关人员
        }
    }

    public void processCreditCardPayment(Order order) {
        processPaymentWithLoggingAndExceptionHandling(order, () -> {
        // 信用卡支付逻辑
        System.out.println("Processing credit card payment for order: " + order.getId());
        // 假设这里有复杂的支付逻辑
        });
    }

    public void processAlipayPayment(Order order) {
        processPaymentWithLoggingAndExceptionHandling(order, () -> {
        // 支付宝支付逻辑
        System.out.println("Processing Alipay payment for order: " + order.getId());
        // 假设这里有复杂的支付逻辑
        });
    }
}

简单点描述,抽取公用方法是好事,但是不能为了公用用法,而去动到原来的逻辑,一定要做好兼容性测试。
以前一位同事,抽了一个公用方法,本来有A和B两个url入口,调用进来的,然后抽了公用方法,测试也只是校验了B方法,因为B才是本次需求改动,但是因为抽公用方法,影响了A接口导致出问题。
7. 接口新增入参、出参
平时做需求时,这个太常见了。新增入参字段,或者新增字段返回。入参、出参新增,这里还是做好三步曲:

  • 更新文档,说明修改了哪些内容
  • 通知上下游,说明原因,场景
  • 分析兼容性影响,联调测试

8. 修改老接口时,思考接口的兼容性
很多bug都是因为修改了对外老接口,但是却不做兼容导致的。关键这个问题多数是比较严重的,可能直接导致系统发版失败的。
所以,如果需求是在原来接口上修改,尤其这个接口是对外提供服务的话,一定要考虑接口兼容。举个例子吧,比如dubbo接口,原本是只接收A,B参数,现在加了一个参数C,就可以考虑这样处理。

//老接口
void oldService(A,B);{
//兼容新接口,传个null代替C
newService(A,B,null);
}

//新接口,暂时不能删掉老接口,需要做兼容。
void newService(A,B,C);

总结:

  • 更新文档,说明修改了哪些内容
  • 通知上下游,说明原因,场景
  • 分析兼容性影响,联调测试
posted @ 2024-11-29 16:29  李若盛开  阅读(18)  评论(0编辑  收藏  举报