最推荐将版本号写入请求路径,如/api/v1/users;其次可用请求头(如X-API-Version)或媒体类型协商;Spring Profiles和网关路由适合作为补充,参数方式不推荐。

最常用也最推荐的方式是把版本号直接写进请求路径,比如 /api/v1/users 和 /api/v2/users。这种方式直观、易调试、兼容性好,客户端和网关都容易识别和路由,是生产环境的主流选择。
URL 路径中嵌入版本号
这是实现最简单、维护成本最低的方式。每个版本对应一个独立的 Controller 或包路径:
- 用
@RequestMapping("/api/v1")标记 V1 控制器,@RequestMapping("/api/v2")标记 V2 控制器 - 不同版本可使用不同 Service 实现类(如
UserV1Service和UserV2Service),配合@Qualifier("v1")注入 - 注意避免路径重复或混淆,建议统一前缀(如
/api)再加版本段,便于 Nginx 或 Spring Cloud Gateway 做路由分发
通过请求头区分版本
适合不想暴露版本信息给客户端、或希望保持 URI 纯净的场景。常见做法是约定自定义 Header:
- 客户端发送
X-API-Version: v2或Accept: application/vnd.myapp.v2+json - 服务端通过自定义
RequestCondition+@ApiVersion注解,在方法级别做匹配 - 需确保所有接口都校验该 Header,否则容易漏掉版本逻辑;测试和文档也要同步体现 Header 要求
媒体类型(Content-Type / Accept)协商
遵循 REST 内容协商规范,语义更标准,但对客户端要求更高:
- 例如接受
Accept: application/vnd.mycompany.users+json;version=2.0 - 需要扩展
RequestMappingHandlerMapping或使用Produces+ 自定义ContentNegotiationManager - 优势是 URL 不变、支持同一资源多表示;缺点是调试不便(curl 需手动加 Header)、部分前端库默认不设 Accept
其他可行但较少单独使用的方案
这些通常作为补充或基础设施层配合使用:
-
Spring Profiles:用
@Profile("v2")隔离配置或 Bean,适合整体行为切换(如数据库 schema、第三方 SDK 版本),但不适用于细粒度接口控制 -
网关层路由:Spring Cloud Gateway 或 Nginx 根据路径前缀(
/v1/**)转发到不同服务实例,适合微服务拆分后按版本部署 - 参数方式(如 ?version=v2):不推荐——破坏 REST 资源标识原则,缓存、日志、安全策略都可能出问题











