1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

        Asp-Net-Core開發(fā)筆記:API版本管理

        共 8164字,需瀏覽 17分鐘

         ·

        2023-06-07 08:32

        1 前言

        對于Web API應(yīng)用程序而言,隨著時間的推移以及需求的增加或改變,API必然會遇到升級的需求。事實上,Web API應(yīng)用程序應(yīng)該從創(chuàng)建時就考慮到API版本的問題。業(yè)務(wù)的調(diào)整、功能的增加、接口的移除與改名、接口參數(shù)變動、實體屬性的添加、刪除和更改等都會改變API的功能,從而帶來版本的變更。

        現(xiàn)有的資料大部分是使用 Microsoft.AspNetCore.Mvc.Versioning 這個包,但我實際使用的時候發(fā)現(xiàn)這個包早就不更新了,微軟官方文檔好像也沒有這部分介紹,不過在這個包的nuget主頁上有說已經(jīng)換成新的 Asp.Versioning.Mvc 包,原來是微軟改名部發(fā)力了,失敬失敬~ ??

        好在這個新的包在Github上有很詳細(xì)的文檔,但這改名速度實在是猛,為了實現(xiàn)這個功能,我走了不少彎路。??

        OK,本文基于 .Net6.0,以 AspNetCore WebApi 為例,介紹引入API版本管理的過程。

        2 基礎(chǔ)

        指定版本的方法有兩種,既可以使用[ApiVersion]特性,也可以使用版本約定方式。當(dāng)定義了不同版本的API接口后,客戶端可以通過如下多種方式來訪問某一版本的API。

        • 使用URL路徑,如 api/v1.0/values
        • 使用查詢字符串,如 api/values?api-version=1.0
        • 使用HTTP自定義消息頭
        • 使用媒體類型(Media Type)參數(shù),如 Accept: application/json;v=2.0

        ASP.NET Core MVC默認(rèn)的方式是使用查詢字符串,查詢字符串使用的參數(shù)名為api-version。具體使用哪種方式由服務(wù)端指定(用下面介紹的 ApiVersionReader 屬性來配置),既可以使用其中的一種,也可以同時使用多種不同的方式。

        API版本的格式由主版本號與次版本號組成,此外還可以包含可選的兩部分:版本組和狀態(tài)。

        • [Version Group.].[-Status]
        • [[.Minor]][-Status]

        版本組的格式為YYYY-MM-DD,它能夠?qū)PI接口起到邏輯分組的作用,狀態(tài)則能夠標(biāo)識當(dāng)前版本的狀況,如Alpha、Beta和RC等。以下是常見的版本格式:

        • /api/foo?api-version=1.0
        • /api/foo?api-version=2.0-Alpha
        • /api/foo?api-version=2015-05-01.3.0
        • /api/v1/foo
        • /api/v2.0-Alpha/foo
        • /api/v2015-05-01.3.0/foo

        本文采用 /api/v1/foo 形式

        3 安裝依賴

        需要安裝這倆nuget包

        • Asp.Versioning.Mvc
        • Asp.Versioning.Mvc.ApiExplorer

        4 注冊服務(wù)

        編輯 Program.cs 文件

              builder.Services.AddApiVersioning(options?=>?{
        ??options.DefaultApiVersion?=?new?ApiVersion(1,?0);
        ??options.AssumeDefaultVersionWhenUnspecified?=?true;
        ??options.ReportApiVersions?=?true;
        ??options.ApiVersionReader?=?ApiVersionReader.Combine(
        ????new?UrlSegmentApiVersionReader(),
        ????new?HeaderApiVersionReader("x-api-version"),
        ????new?MediaTypeApiVersionReader("ver")
        ??);
        })
        ??.AddMvc()
        ??.AddApiExplorer(options?=>?{
        ????options.GroupNameFormat?=?"'v'VVV";
        ????options.SubstituteApiVersionInUrl?=?true;
        ??});

        以上代碼做了這些事:

        • DefaultApiVersion 設(shè)置默認(rèn)版本為1.0
        • AssumeDefaultVersionWhenUnspecified 沒有指定版本時,使用默認(rèn)版本
        • ReportApiVersions 在響應(yīng)頭里加上可用的接口版本
        • ApiVersionReader 定義了可以從三個地方獲取接口版本信息,URL里和倆請求頭
        • GroupNameFormat 指定了版本名稱格式,詳見下表
        • SubstituteApiVersionInUrl 因為要使用URL指定版本,所以這里設(shè)置為true

        API Version Format Strings

        本文中我使用的是 'v'VVV 的格式

        Format Specifier Description Examples
        F Full API version as [group version][.major[.minor]][-status] 2017-05-01.1-RC -> 2017-05-01.1-RC
        FF Full API version with optional minor version as [group version][.major[.minor,0]][-status] 2017-05-01.1-RC -> 2017-05-01.1.0-RC
        G Group version as yyyy-MM-dd 2017-05-01.1-RC -> 2017-05-01
        GG Group version as yyyy-MM-dd with status 2017-05-01.1-RC -> 2017-05-01-RC
        y Group version year from 0 to 99 2001-05-01.1-RC -> 1
        yy Group version year from 00 to 99 2001-05-01.1-RC -> 01
        yyy Group version year with a minimum of three digits 2017-05-01.1-RC -> 017
        yyyy Group version year as a four-digit number 2017-05-01.1-RC -> 2017
        M Group version month from 1 through 12 2001-05-01.1-RC -> 5
        MM Group version month from 01 through 12 2001-05-01.1-RC -> 05
        MMM Group version abbreviated name of the month 2001-06-01.1-RC -> Jun
        MMMM Group version full name of the month 2001-06-01.1-RC -> June
        d Group version day of the month, from 1 through 31 2001-05-01.1-RC -> 1
        dd Group version day of the month, from 01 through 31 2001-05-01.1-RC -> 01
        ddd Group version abbreviated name of the day of the week 2001-05-01.1-RC -> Mon
        dddd Group version full name of the day of the week 2001-05-01.1-RC -> Monday
        v Minor version 2001-05-01.1-RC -> 1 1.1 -> 1
        V Major version 1.0-RC -> 1 2.0 -> 2
        VV Major and minor version 1-RC -> 1 1.1-RC -> 1.1 1.1 -> 1.1
        VVV Major, optional minor version, and status 1-RC -> 1-RC 1.1 -> 1.1
        VVVV Major, minor version, and status 1-RC -> 1.0-RC 1.1 -> 1.1 1 -> 1.0
        S Status 1.0-Beta -> Beta
        p Padded minor version with default of two digits 1.1 -> 01 1 -> 00
        p[n] Padded minor version with N digits p2: 1.1 -> 01 p3: 1.1 -> 001
        P Padded major version with default of two digits 2.1 -> 02 2 -> 02
        P[n] Padded major version with N digits P2: 2.1 -> 02 P3: 2.1 -> 002
        PP Padded major and minor version with a default of two digits 2.1 -> 02.01 2 -> 02.00
        PPP Padded major, optional minor version, and status with a default of two digits 1-RC -> 01-RC 1.1-RC -> 01.01-RC
        PPPP Padded major, minor version, and status with a default of two digits 1-RC -> 01.00-RC 1.1-RC -> 01.01-RC

        5 設(shè)置API版本

        例子接口有倆版本

        • /api/v1/demo/test
        • /api/v2/demo/test

        在 Controller 下創(chuàng)建倆目錄,v1 和 v2,然后分別創(chuàng)建Controller

        上代碼 Controllers/v1/DemoController.cs

              [Route("api/v{version:apiVersion}/[controller]")]
        [ApiVersion(1.0)]
        [ApiController]
        public?class?DemoController?:?ControllerBase?{
        ??[HttpGet("[action]")]
        ??public?ApiResponse?Test()?{
        ????return?ApiResponse.Ok("version=1.0");
        ??}
        }

        另一個版本的接口 Controllers/v2/DemoController.cs

              [Route("api/v{version:apiVersion}/[controller]")]
        [ApiVersion(2.0)]
        [ApiController]
        public?class?DemoController?:?ControllerBase?{
        ??[HttpGet("[action]")]
        ??public?ApiResponse?Test()?{
        ????return?ApiResponse.Ok("version=2.0");
        ??}
        }

        可以看到要區(qū)分不同版本的接口,只需要添加 [ApiVersion(2.0)] 特性即可。

        因為我要使用URL來選擇不同版本的接口,所以要把路由配置為 "api/v{version:apiVersion}/[controller]"

        如果不把版本號寫在URL里,也可以用請求參數(shù)傳遞,比如 /api/demo/test?api-version=1.0

        這些可以在 ApiVersionReader 屬性配置

        6 配置Swagger

        swagger基本已經(jīng)是接口文檔的標(biāo)準(zhǔn)了,但我發(fā)現(xiàn)很多文章都沒有介紹swagger這塊。(還好官方文檔沒有忘記)

        首先創(chuàng)建一個配置類

              public?class?ConfigureSwaggerOptions?:?IConfigureOptions<SwaggerGenOptions>?{
        ??readonly?IApiVersionDescriptionProvider?provider;

        ??public?ConfigureSwaggerOptions(IApiVersionDescriptionProvider?provider)?=>
        ????this.provider?=?provider;

        ??public?void?Configure(SwaggerGenOptions?options)?{
        ????foreach?(var?description?in?provider.ApiVersionDescriptions)?{
        ??????options.SwaggerDoc(
        ????????description.GroupName,
        ????????new?OpenApiInfo()?{
        ??????????Title?=?$"Example?API?{description.ApiVersion}",
        ??????????Version?=?description.ApiVersion.ToString(),
        ????????});
        ????}
        ??}
        }

        注冊服務(wù)

              builder.Services.AddTransient,?ConfigureSwaggerOptions>();

        配置中間件

              app.UseSwagger();
        app.UseSwaggerUI(options?=>?{
        ????foreach?(var?description?in?app.DescribeApiVersions())?{
        ????????var?url?=?$"/swagger/{description.GroupName}/swagger.json";
        ????????var?name?=?description.GroupName.ToUpperInvariant();
        ????????options.SwaggerEndpoint(url,?name);
        ????}
        });

        7 效果 & 測試

        搞定,訪問swagger文檔,在右上角接口分組可以看到不同版本

        529ea8644ae80b31998b86ad68b2fdf8.webp

        請求 https://localhost:7053/api/v1/Demo/Test

        接口返回

              {
        ??"statusCode":?200,
        ??"successful":?true,
        ??"message":?"version=1.0",
        ??"data":?null,
        ??"errorData":?null
        }

        請求 https://localhost:7053/api/v2/Demo/Test

        接口返回

              {
        ??"statusCode":?200,
        ??"successful":?true,
        ??"message":?"version=2.0",
        ??"data":?null,
        ??"errorData":?null
        }

        不錯~ ??

        8 參考資料

        • https://github.com/dotnet/aspnet-api-versioning/wiki


        瀏覽 55
        點(diǎn)贊
        評論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報
        評論
        圖片
        表情
        推薦
        點(diǎn)贊
        評論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            亚洲天堂网一区二区三区 | 四虎永久在线精品无码 | 欧美激情老妇一二区 | 国产免费无码一区二区 | 最近中文字幕在线观看 | 免费无码婬片AAAA片直播中文 | 啪啪啪免费观看网站 | 啊啊啊啊啊网站 | 成人国产激情视频 | 女同被羞羞动漫女同 |