Skip to main content
 首页 » 编程设计

web-services之您的 WebService 版本控制最佳实践是什么

2025年05月04日106zdz8207

我们有 2 个独立的产品需要通过 Web 服务相互通信。
支持 API 版本控制的最佳实践是什么?

我有 this article从 2004 年开始声称没有实际标准,只有最佳实践。有更好的解决方案吗?你如何解决 WS 版本控制?

问题描述

系统 A

客户

class SystemAClient{ 
    SystemBServiceStub systemB; 
    public void consumeFromB(){ 
        SystemBObject bObject = systemB.getSomethingFromB(new SomethingFromBRequest("someKey")); 
 
    } 
} 

服务
class SystemAService{ 
    public SystemAObject getSomethingFromA(SomethingFromARequest req){ 
        return new SystemAObjectFactory.getObject(req); 
    } 
} 

可转移对象

版本 1
class SystemAObject{ 
     Integer id; 
     String name; 
     ... // getters and setters etc; 
} 

版本 2
class SystemAObject{ 
     Long id; 
     String name; 
     String description; 
     ... // getters and setters etc; 
} 

请求对象

版本 1
class SomethingFromARequest { 
     Integer requestedId; 
     ... // getters and setters etc; 
 
} 

版本 2
class SomethingFromARequest { 
     Long requestedId; 
     ... // getters and setters etc; 
 
} 

系统 B

客户
class SystemBClient{ 
    SystemAServiceStub systemA; 
    public void consumeFromA(){ 
        SystemAObject aObject = systemA.getSomethingFromA(new SomethingFromARequest(1)); 
        aObject.getDescription() // fail point 
        // do something with it... 
    } 
} 

服务
class SystemBService{ 
    public SystemBObject getSomethingFromB(SomethingFromBRequest req){ 
        return new SystemBObjectFactory.getObject(req); 
    } 
} 

可转移对象

版本 1
class SystemBObject{ 
     String key; 
     Integer year; 
     Integer month; 
     Integer day; 
 
     ... // getters and setters etc; 
} 

版本 2
class SystemBObject{ 
     String key; 
     BDate date; 
     ... // getters and setters etc; 
} 
 
class BDate{ 
     Integer year; 
     Integer month; 
     Integer day; 
     ... // getters and setters etc; 
 
} 

请求对象

版本 1
class SomethingFromBRequest { 
     String key; 
     ... // getters and setters etc; 
} 

版本 2
class SomethingFromBRequest { 
     String key; 
     BDate afterDate; 
     BDate beforeDate; 
     ... // getters and setters etc; 
} 

失败场景

如果一个 系统A 的客户版本 1 调用 B系统 的服务版本 2 它可能会失败:
  • SystemBObject 上缺少方法( getYear() , getMonth() , getDay() )
  • 未知类型BDate

  • 如果一个 系统A 的客户版本 2 调用 B系统 的服务版本 1 它可能会失败:
  • 未知类型BDateSomethingFromBRequest (A 客户端使用 B 版本 1 无法识别的较新的 B 请求对象)
  • 如果系统 A 客户端足够聪明,可以使用请求对象的版本 1,它可能会因缺少 SystemBObject 上的方法而失败。对象(getDate())

  • 如果一个 B系统 的客户版本 1 调用 系统A 的服务版本 2 它可能会失败:
  • SystemAObject 上的类型不匹配或溢出(返回 Long 但预期 Integer )

  • 如果一个 B系统 的客户版本 2 调用 系统A 的服务版本 1 它可能会失败:
  • SystemARequest 上的类型不匹配或溢出(请求 Long 而不是 Integer )
  • 如果请求以某种方式通过,则转换问题( stub 为 Long,但服务返回 Integer 不一定与所有 WS 实现兼容)

  • 可能的解决方案
  • 升级版本时使用数字:例如SystemAObject1 , SystemBRequest2等等,但这缺少一个用于匹配源/目标版本的 API
  • 在签名中,传递 XML 而不是对象(糟糕,在 XML 中传递转义的 XML、双重序列化、反序列化/解析、反解析)
  • 其他:例如Document/literal/WS-I 有补救措施吗?
  • 请您参考如下方法:

    我更喜欢 Salesforce.com 的版本控制方法。每个版本的 Web 服务都有一个不同的 URL,格式如下:

    http://api.salesforce.com/{version}/{serviceName} 
    

    因此,您将拥有如下所示的 Web 服务 URL:
    http://api.salesforce.com/14/Lead 
     
    http://api.salesforce.com/15/Lead 
    

    等等...

    使用这种方法,您可以获得以下好处:
  • 你总是知道你在说哪个版本。
  • 保持向后兼容性。
  • 您不必担心依赖问题。每个版本都有完整的服务集。您只需要确保不会在调用之间混合版本(但这取决于服务的消费者,而不是您作为开发人员)。