【发布时间】:2013-12-10 11:40:10
【问题描述】:
我一直在寻找如何使用 Spring 3.2.x 管理 REST API 版本,但我没有找到任何易于维护的东西。我将首先解释我遇到的问题,然后是解决方案……但我想知道我是否在这里重新发明了轮子。
我想根据 Accept 标头管理版本,例如,如果请求具有 Accept 标头 application/vnd.company.app-1.1+json,我希望 spring MVC 将其转发给处理此版本的方法。而且由于并非 API 中的所有方法都在同一个版本中更改,因此我不想转到每个控制器并更改版本之间未更改的处理程序的任何内容。我也不希望有逻辑来确定在控制器本身中使用哪个版本(使用服务定位器),因为 Spring 已经在发现要调用的方法。
因此采用了 1.0 到 1.8 版本的 API,其中处理程序在 1.0 版本中引入并在 v1.7 中进行了修改,我想通过以下方式处理这个问题。想象一下代码在控制器内部,并且有一些代码能够从标头中提取版本。 (以下在Spring中无效)
@RequestMapping(...)
@VersionRange(1.0,1.6)
@ResponseBody
public Object method1() {
// so something
return object;
}
@RequestMapping(...) //same Request mapping annotation
@VersionRange(1.7)
@ResponseBody
public Object method2() {
// so something
return object;
}
这在 spring 中是不可能的,因为这 2 个方法具有相同的 RequestMapping 注释并且 Spring 无法加载。这个想法是VersionRange 注释可以定义一个开放或封闭的版本范围。第一种方法从 1.0 到 1.6 版本有效,而第二种方法适用于 1.7 及以上版本(包括最新版本 1.8)。我知道如果有人决定通过 99.99 版,这种方法就会失效,但我可以接受。
现在,如果不认真修改 spring 的工作原理,上述内容是不可能的,我正在考虑修改处理程序与请求匹配的方式,特别是编写我自己的ProducesRequestCondition,并在其中包含版本范围.例如
代码:
@RequestMapping(..., produces = "application/vnd.company.app-[1.0-1.6]+json)
@ResponseBody
public Object method1() {
// so something
return object;
}
@RequestMapping(..., produces = "application/vnd.company.app-[1.7-]+json)
@ResponseBody
public Object method2() {
// so something
return object;
}
通过这种方式,我可以在注释的产生部分定义封闭或开放的版本范围。我现在正在研究这个解决方案,问题是我仍然需要替换一些我不喜欢的核心 Spring MVC 类(RequestMappingInfoHandlerMapping、RequestMappingHandlerMapping 和 RequestMappingInfo),因为这意味着无论何时都需要额外的工作我决定升级到更新版本的 spring。
如果有任何想法,我将不胜感激……尤其是任何以更简单、更易于维护的方式执行此操作的建议。
编辑
添加赏金。要获得赏金,请回答上面的问题,而不建议在控制器本身中使用此逻辑。 Spring 已经有很多逻辑可以选择调用哪个控制器方法,我想捎带它。
编辑 2
我在 github 上分享了原始 POC(有一些改进):https://github.com/augusto/restVersioning
【问题讨论】:
-
@flup 我不明白你的评论。这只是说您可以使用标头,正如我所说,spring 提供的开箱即用的功能不足以支持不断更新的 API。更糟糕的是,该答案上的链接使用了 URL 中的版本。
-
我们需要支持多个版本的 API,这些差异通常是一些细微的变化,会使某些客户端的某些调用不兼容(如果我们需要支持 4 个小版本,这并不奇怪,其中一些端点不兼容)。我很欣赏将它放在 url 中的建议,但我们知道这是朝着错误方向迈出的一步,因为我们有几个应用程序的版本在 URL 中,并且每次我们需要提升时都会涉及很多工作版本。
-
@Augusto,实际上你还没有。只需以不破坏向后兼容性的方式设计您的 API 更改。只需举出破坏兼容性的更改示例,我将向您展示如何以不破坏的方式进行这些更改。
-
您是否看过stackoverflow.com/a/10336769/2615437,这似乎暗示您的陈述“这在spring 中是不可能的,因为这两种方法具有相同的RequestMapping 注释并且Spring 无法加载。”不完全正确?
标签: java spring rest spring-mvc versioning