在实际工作中,由于接口功能做了不兼容变更,因此需要在原接口基础上增加版本控制,以示区分。
何时进行版本控制?这里引用REST API版本控制描述
只有在进行重大更改时才需要对API进行升级。突破性变化包括:
- 一个或多个调用的响应数据格式的变化
- 响应类型的更改(即将整数更改为float)
- 删除API的任何部分。
中断更改应始终导致更改API或内容响应类型的主版本号。
不间断更改(例如添加新端点或新响应参数)不需要更改主版本号。但是,在进行更改以跟踪可能正在接收缓存版本数据或可能遇到其他API问题的客户时,跟踪API的次要版本会很有帮助。
1. 常见版本控制策略
方式 | 说明 |
---|---|
子域名 | 不同版本使用不同域名,v1.test.com,v2.test.com |
请求URL | 同一域名,不同路径,test.com/v1/,test.com/v2/ |
请求参数 | 根据参数区分相应功能 |
2. 设计建议
- 历史版本的支持需要有一定时间限制,超时将不再支持,否则随着新版本的不断迭代,维护将是一件头疼的事情。
- 尽量将功能的颗粒度降到最低,降低功能间的耦度。
- 新版本建议分类存储,在线API文档避免杂乱无章,可考虑分组展示。
3. 实现
通过重写RequestMappingHandlerMapping
更改URL分发
- 核心实现
public class VersionConfig extends WebMvcConfigurationSupport {
/**
* 注解@Version(2)将分发至 /v2/** 默认: /v1/** || /**
*
* @param contentNegotiationManager
* @param conversionService
* @param resourceUrlProvider
* @return
*/
@Override
public RequestMappingHandlerMapping requestMappingHandlerMapping(ContentNegotiationManager contentNegotiationManager, FormattingConversionService conversionService, ResourceUrlProvider resourceUrlProvider) {
return new RequestMappingHandlerMapping() {
@Override
protected RequestMappingInfo getMappingForMethod(Method method, Class<?> type) {
RequestMappingInfo rmi = super.getMappingForMethod(method, type);
if (Objects.isNull(rmi)) {
return null;
}
Version version = Optional.ofNullable(AnnotationUtils.findAnnotation(method, Version.class)).orElseGet(() -> AnnotationUtils.findAnnotation(type, Version.class));
return Objects.nonNull(version)
? RequestMappingInfo.paths(Arrays.stream(version.value()).mapToObj(i -> "v" + i).toArray(String[]::new)).build().combine(rmi)
: RequestMappingInfo.paths(new String[]{"v1", ""}).build().combine(rmi);
}
};
}
}
网友评论