• WebApi的多版本管理


    什么是 API 的多版本问题?Android 等 App 存在着多版本客户端共存的问题:App 最新版已经升级到了 5.0 了,但是有的用户手机上还运行着 4.8、3.9 甚至 2.2 版本的 App,由于早期没有内置升级机制、用户不会升级、用户拒绝升级等原因,造成这些旧版本 App 也在运行。开发新版本 App 的时候,要给接口增加新的功能或者修改以前接口的规范,会造成旧版本 App 无法使用,因此在一定情况下会“保留旧接口的运行、新功能用新接口”,这样就会存在多版本接口共存的问题。

     通常的做法是:旧版接口做一个代码分支,除了进行 bug 修改外,旧版本接口不再做改动;新接口代码继续演化升级。在客户端请求的时候带着要请求的接口版本号,在服务器端选择合适的版本代码进行处理。

    技术处理方法:

    1、  (最推荐)不同版本用不同的域名:v1.api.rsfy.com、v2.api.rsfy.com、v3……;

    2、  在 url、报文头等中带不同的版本信息,用 Nginx 等做反向代理服务器,然后将 http://api.rsfy.com/api/v1/User/1http://api.rsfy.com/api/v2/User/1到不同的服务器处理。

    3、  多个版本的 Controller 共处在一个项目中,然后使用 [RoutePrefix] 或者

    IHttpControllerSelector 根据报文头、路径等选择不同的 Controller 执行。下面主要讲这方法

     (推荐):自定义 IHttpControllerSelector

    修改默认路由,如果还想用{controller}/{action}的方式,那么改就是了

    其中v1,v2代表这版本号,不同版本的 Controller 放到不同的 namespace 下

     config.Routes.MapHttpRoute(
                    name: "DefaultApiv1",
                    routeTemplate: "api/v1/{controller}/{action}/{id}",
                    defaults: new { id = RouteParameter.Optional });
    
                config.Routes.MapHttpRoute(
                    name: "DefaultApiv2",
                    routeTemplate: "api/v2/{controller}/{action}/{id}", defaults: new { id = RouteParameter.Optional }
                );

    首先自定义类VersionControllerSelector继承DefaultHttpControllerSelector

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Net.Http;
    using System.Text.RegularExpressions;
    using System.Web;
    using System.Web.Http;
    using System.Web.Http.Controllers;
    using System.Web.Http.Dispatcher;
    
    namespace ApiDemo
    {
        public class VersionControllerSelector:DefaultHttpControllerSelector
        {
            private readonly HttpConfiguration _config;
    
            public VersionControllerSelector(HttpConfiguration config) : base(config)
            {
                _config = config;
            }
    
            public override IDictionary<string, HttpControllerDescriptor> GetControllerMapping()
            {
                Dictionary<string, HttpControllerDescriptor> dict = new Dictionary<string, HttpControllerDescriptor>();
                foreach (var asm in _config.Services.GetAssembliesResolver().GetAssemblies())
                {
                    //获取所有继承自ApiController的非抽象类 
                    var controllerTypes = asm.GetTypes()
                        .Where(t => !t.IsAbstract && typeof(ApiController)
                        .IsAssignableFrom(t)).ToArray();
    
                    foreach (var ctrlType in controllerTypes)
                    {
                        //从namespace中提取出版本号                  命名空间,有可能不是当前的weiapi项目
                        var match = Regex.Match(ctrlType.Namespace, GetType().Namespace + @".Controllers.v(d+)");
                        if (match.Success)
                        {
                            string verNum = match.Groups[1].Value;//获取版本号  
                            //从PersonController中拿到Person
                            string ctrlName = Regex.Match(ctrlType.Name, "(.+)Controller").Groups[1].Value;
                            //Personv2为key                
                            string key = ctrlName + "v" + verNum;
    
                            dict[key] = new HttpControllerDescriptor(_config, ctrlName, ctrlType);
                        }
                    }
                }
                return dict;
            }
    
            //设计就是返回HttpControllerDesriptor的过程 
            public override HttpControllerDescriptor SelectController(HttpRequestMessage request)
            {
                //获取所有的controller键值集合 
                var controllers = GetControllerMapping();
                //获取路由数据 
                var routeData = request.GetRouteData();
                //从路由中获取当前controller的名称 
                var controllerName = (string)routeData.Values["controller"];
    
                var verNum = request.Headers.TryGetValues("ApiVersion", out var versions) ?
                    versions.Single() :
                    Regex.Match(request.RequestUri.PathAndQuery, @"api/v(d+)").Groups[1].Value;
    
    
                //获取版本号 
    
                var key = controllerName + "v" + verNum;//获取Personv2             
                return controllers.ContainsKey(key) ? controllers[key] : null;
            }
        }
    }

    然后在WebApiConfig 的 Register 中添加

     config.Services.Replace(typeof(IHttpControllerSelector), new VersionControllerSelector(config));

    最后我们就可以以不同的版本号,来访问不同的controller了。

  • 相关阅读:
    优化索引的常用思路
    MySQL架构说明
    Mysql性能分析必备知识
    查询截取分析
    Mysql之explain
    MyISAM和InnDB的区别
    sql执行顺序(面试常见)
    一个ES设置操作引发的“血案”
    Ubuntu 安装搜狗拼音输入法
    ubuntu 安装SecoClient x64
  • 原文地址:https://www.cnblogs.com/shx666/p/7898381.html
Copyright © 2020-2023  润新知