PAYATHON 2026

REST client 中检查 REST 方法版本支持的最佳实践是什么?

技术老齐

建议采用第二种方式:封装版本比较和异常抛出逻辑,在每个受版本限制的方法入口保留一行检查。这样可以直接看出方法的使用条件,比较规则和错误信息也能统一维护。

前提是功能从某个版本引入后,在后续兼容版本中一直可用。如果功能还受授权、部署配置或功能开关影响,就需要检查服务端能力,单靠版本号不够。

为什么更适合封装检查逻辑

只有一两个方法需要检查时,直接写 if 也很清楚。随着受限方法增加,版本解析、比较方式、异常类型和错误信息会反复出现在各个方法中,后续维护容易出现不一致。

每个方法可以声明自己的版本要求,由辅助方法执行检查:

EnsureApiVersionAtLeast(requiredVersion, operationName);

这个名称比 checkForVersionSupport 更具体,说明了最低版本要求,也表明检查失败后不会继续执行。每个方法仍需声明自己的限制,这部分重复有实际意义,不必为了省掉一行代码引入复杂机制。

先确定版本信息的含义

客户端应检查目标服务端的 API 版本,或与 API 兼容性有明确映射关系的软件版本。客户端自身的发布版本无法说明服务端支持哪些操作。

实现时可以按以下顺序处理:

  1. 初始化连接时,通过服务端已有的版本查询机制获取版本。
  2. 按约定格式解析版本,保存在对应的客户端实例中。
  3. 在受限方法入口执行检查,通过后再发送请求。
  4. 如果服务端可能在连接期间升级,约定重新连接或刷新版本信息的时机。

如果目前只能获取软件版本,就需要维护软件版本与 API 功能的对应关系,不能默认软件版本号与 API 协议版本号相同。

C# 示例:保留入口检查,统一比较和异常

示例沿用问题中的 2.5.3 作为最低版本,假设版本号由纯数字分段组成,且该操作在后续兼容版本中一直受支持。Data 和 doApiStuffWith 使用客户端已有的定义,HTTP 请求实现省略。

using System;

public partial class RestClient
{
    private static readonly Version ApiStuffMinimumVersion =
        new Version(2, 5, 3);

    private readonly Version _serverApiVersion;

    public RestClient(Version serverApiVersion)
    {
        _serverApiVersion = serverApiVersion
            ?? throw new ArgumentNullException(nameof(serverApiVersion));
    }

    public void apiStuff(Data input)
    {
        EnsureApiVersionAtLeast(
            ApiStuffMinimumVersion,
            nameof(apiStuff));

        doApiStuffWith(input);
    }

    private void EnsureApiVersionAtLeast(
        Version minimumVersion,
        string operationName)
    {
        if (_serverApiVersion.CompareTo(minimumVersion) < 0)
        {
            throw new NotSupportedException(
                $"{operationName} requires server API version " +
                $"{minimumVersion} or later. " +
                $"Current version: {_serverApiVersion}.");
        }
    }
}

这里用 NotSupportedException 表示目标服务端不支持该操作,比直接抛出宽泛的 Exception 更明确。如果调用方需要读取当前版本、所需版本或功能标识,可以再定义带这些属性的专用异常。

版本号应先解析再比较。C# 的 string 不支持示例中的 < 运算符;即使改用字符串比较,也可能把 "2.10" 排在 "2.9" 前面。System.Version.CompareTo 会按数值分量比较版本。Microsoft 文档

使用 System.Version 时还要统一版本格式:它会把 2.5 视为早于 2.5.0。只有协议明确规定省略分量等于零时,才应自行补齐。对于带有 -beta 等预发布标记的版本,需要使用符合实际版本规则的解析器。System.Version 文档

哪些情况适合采用其他设计

功能与版本不严格对应:检查能力

如果旧版本可能回移新功能,或者同一版本的不同部署提供不同能力,建议由服务端通过约定的元数据声明支持哪些功能。

客户端方法可以改为:

public void apiStuff(Data input)
{
    EnsureSupported(ApiFeature.ApiStuff);
    doApiStuffWith(input);
}

ApiFeature 和 EnsureSupported 只是客户端设计示意,需要自行实现。如果还要根据服务端版本推导能力,可以把映射集中放在能力判断组件中,避免各个方法分别维护规则。

调用方需要提前禁用按钮或选择替代操作时,可以额外提供 Supports(ApiFeature.ApiStuff) 这样的查询接口。方法内部仍应保留检查,确保其他调用方也遵守限制。

同一操作在不同版本中实现不同:使用适配器

如果新版本只是比旧版本增加了少量方法,辅助检查通常就够用。

如果同一操作在不同版本中的 URL、请求字段或响应结构都有变化,可以为不同协议版本提供适配器,并在初始化时选择实现。公共客户端接口保持稳定,各适配器负责具体请求和数据转换,业务方法就不必包含大量版本分支。

只有旧操作能完整保留新操作的语义时,才适合自动降级。无法保留的行为应明确报错,避免返回表面成功、含义却不同的结果。

容易遗漏的边界

最低版本检查只能表达“从这个版本开始支持”。如果将来的主版本移除了操作或改变了协议,version >= minimumVersion 仍会通过。应根据实际契约检查兼容版本范围,或交由能力判断和适配器处理。

客户端预检查无法保证请求一定成功。服务端配置可能变化,缓存的版本信息也可能过期,因此仍需处理实际响应。不能仅凭 404 就断定版本太旧,它也可能表示路径或资源不存在;应依据 API 约定的错误码判断。

版本缺失或解析失败时,应明确报告无法确认兼容性,或按产品约定采取保守策略。不要把未知版本默认为支持全部功能,也不要通过执行有副作用的操作探测支持情况。

验证时应重点覆盖低于最低版本、恰好等于最低版本、兼容的更高版本,以及版本信息无效的情况。对于被拒绝的调用,还应确认客户端没有发送实际请求。

备注:内容仅供参考。