2.解决方式 1.不同版本用不同的域名: v1.api.rsfy.com 、 v2.api.rsfy.com 、 v3

时间:2022-04-26 08:50:57

1.多版本打点观点

什么是API的多版本问题?Android等App存在着多版本客户端共存的问题:由于早期没有内置升级机制,用户不会升级,拒绝升级等原因,造成了许多软件的旧版本App也在运行。开发新版本App时,要给接口增加新的成果或者改削以前接口的规范,会造成旧版本App无法使用,因此再必然情况下会“保存旧接口的运行,新成果用新接口”,这样就会存在多版本接口共存的问题。

2.解决方法

1.差别版本用差此外域名:v1.api.rsfy.comv2.api.rsfy.comv3……

    2.在Url,,报文头等中带差此外版本信息,用Nginx等做反向代办代理处事,然后将  转到差此外处事器措置惩罚惩罚

     3.多个版本的Controller共处在一个项目中,然后使用[RoutePrefix]或者IHttpControllerSelector按照报文头,路径等选择差此外Controller执行

   下面以第三个种记录一个例子

3.解决例题

  创建一个WebApi项目,在Controllers中创建各个版本的目录

2.解决方式 1.不同版本用不同的域名: v1.api.rsfy.com 、 v2.api.rsfy.com 、 v3

然后我们在每个版本下创建一个Home控制器

2.解决方式 1.不同版本用不同的域名: v1.api.rsfy.com 、 v2.api.rsfy.com 、 v3

public class HomeController : ApiController { [HttpGet] public String GetIndex() { return "这是v1版本的Index"; } }

public class HomeController : ApiController { [HttpGet] public String GetIndex() { return "这是v2版本的Index"; } }

正常情况下,我们是不成以在Controllers中创建目录的,这不切合约定,所以我们必需改写此中代码,让其按照我们需求来选择控制器。 

下面我们创建一个我们本身的IHttpControllerSelector的实现类来替换默认的IHttpControllerSelector。

/// <summary> /// 本身实现IHttpControllerSelector来替换默认IHttpConllerSelector /// </summary> public class VersionConstrollerSelector : IHttpControllerSelector { private readonly HttpConfiguration _conf; public VersionConstrollerSelector(HttpConfiguration configuration) { _conf = configuration; } public IDictionary<string, HttpControllerDescriptor> GetControllerMapping() { throw new NotImplementedException(); } public HttpControllerDescriptor SelectController(HttpRequestMessage request) { throw new NotImplementedException(); } }

IHttpControllerSelector接口有两个要领,

GetControllerMapping():获取措施中所有的Api接口

SelectController(HttpRequestMessage request):匹配请求的路由

下面我们来重写这两个要领

/// <summary> /// 获取所有Controller /// </summary> /// <returns></returns> public IDictionary<string, HttpControllerDescriptor> GetControllerMapping() { Dictionary<String, HttpControllerDescriptor> dict = new Dictionary<string, HttpControllerDescriptor>(); foreach (var item in _conf.Services.GetAssembliesResolver().GetAssemblies()) {//循环所有措施集 //获取所有担任自ApiController的非抽象类 var controllerTypes = item.GetTypes() .Where(y => !y.IsAbstract && typeof(ApiController) .IsAssignableFrom(y)).ToArray(); foreach (var ctrlType in controllerTypes) {//循环措施集中类型 //从namespace中提取出版本号 var match = Regex.Match(ctrlType.Namespace,GetType().Namespace+ @".Controllers.v(\d+)"); if(match.Success) {//匹配告成 //获取版本号 string verNum = match.Groups[1].Value; //从控制器总名称中拿到控制器名称(例: HomeController中获取Home) string ctrlName = Regex.Match(ctrlType.Name, "(.+)Controller").Groups[1].Value; //声明调集中的键 String key = (ctrlName + "v" + verNum).ToLower(); //存储调集值(控制器信息) dict[key] = new HttpControllerDescriptor(_conf, ctrlName, ctrlType); } } } return dict; } /// <summary> /// 进行匹配Controller /// </summary> /// <param>http请求信息</param> /// <returns>匹配告成返回控制器信息,匹配掉败返回null</returns> public HttpControllerDescriptor SelectController(HttpRequestMessage request) { //获取所有的Controller调集 var controllers = GetControllerMapping(); //获取路由数据 var routeData = request.GetRouteData(); //从路由中获取当前controller的名称 var controllerName = routeData.Values["Controller"] as String; //如果请求头中存在ApiVerson信息则总此中获取版本号否则从url中获取版本号 var verNum = request.Headers.TryGetValues("ApiVerson", out var versions) ? versions.Single() : Regex.Match(request.RequestUri.PathAndQuery, @"api/v(\d+)").Groups[1].Value; //获取版本号 var key = (controllerName + "v" + verNum).ToLower();//获取Personv2 //返回控制器信息 return controllers.ContainsKey(key) ? controllers[key] : null; }

  此刻我们这个类实现完成以后我们便可以在WebApiConfig类中的Register要领中替换本来的IHttpControllerSelector