<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          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
          點贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  操逼操逼网 | 天天射天天日天天 | 亚洲五月花 | 天天做天天日天天干 | 91中文字幕在线观看 |