<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
儘管.net6已經發布很久了,但是公司的專案由於種種原因依舊基於.net Framework。伴隨著版本迭代,後端的api介面不斷增多,每次在聯調的時候,前端開發叫苦不迭:“小胖,你們的swagger頁面越來越卡了,快優化優化!”。
先檢視swagger頁面載入耗時:
以上分別是:
swagger載入的卡慢問題,萌生了優化swagger的想法,剛開始按傳統技能在網路上搜尋了一大圈依舊未找到解決方案。幸好swashbuckle開源,還能自己動手分析了。先下載好原始碼GitHub - domaindrivendev/Swashbuckle.WebApi: Seamlessly adds a swagger to WebApi projects!
從上面的圖上不難發現第二次v1的載入是跟在lang.js後面,而lang.js實際上就是用來做漢化。開啟專案中這個檔案
原來是為了新增控制器註釋,重新存取後端取一次介面檔案。在檢視了原始碼js後,得到一個更簡單的方式,頁面的漢化翻譯,是在資料取完頁面已經渲染後才進行的,可直接使用window.swaggerApi.swaggerObject.ControllerDesc。
setControllerSummary: function () { var summaryDict = window.swaggerApi.swaggerObject.ControllerDesc; var id, controllerName, strSummary; $("#resources_container .resource").each(function (i, item) { id = $(item).attr("id"); if (id) { controllerName = id.substring(9); try { strSummary = summaryDict[controllerName]; if (strSummary) { $(item).children(".heading").children(".options").first().prepend('<li class="controller-summary" style="color:green;" title="' + strSummary + '">' + strSummary + '</li>'); } } catch (e) { console.log(e); } } }); },
修改完檔案以後,再看看頁面的載入,已經不會重複去存取v1。
先看看專案的的swagger設定:
GlobalConfiguration.Configuration .EnableSwagger(c => { c.IncludeXmlComments(GetXmlCommentsPath(thisAssembly.GetName().Name)); c.IncludeXmlComments(GetXmlCommentsPath("xxxx.Api.Dto")); c.SingleApiVersion("v1", "xxxx.Api"); c.CustomProvider((defaultProvider) => new CachingSwaggerProvider(defaultProvider)); })
設定不多,其中有個CachingSwaggerProvider,實現了GetSwagger方法自定義返回資料,在這個方法裡可以得知,實際上對api檔案是有做快取處理,v1載入的資料也就是這個SwaggerDocument。這也意味著,v1載入慢的原因出在這裡。
public SwaggerDocument GetSwagger(string rootUrl, string apiVersion) { var cacheKey = string.Format("{0}_{1}", rootUrl, apiVersion); SwaggerDocument srcDoc = null; //唯讀取一次 if (!_cache.TryGetValue(cacheKey, out srcDoc)) { srcDoc = (_swaggerProvider as Swashbuckle.Swagger.SwaggerGenerator).GetSwagger(rootUrl, apiVersion); srcDoc.vendorExtensions = new Dictionary<string, object> { { "ControllerDesc", GetControllerDesc() } }; _cache.TryAdd(cacheKey, srcDoc); } return srcDoc; }
偵錯程式的時候,swashbuckle提供的GetSwagger方法佔據了大量的耗時。將原始碼Swashbuckle.Core參照進來,重新開啟swagger時會有個小問題,資原始檔都報404錯誤,這個是因為嵌入資原始檔沒有找到
<ItemGroup> <EmbeddedResource Include="..swagger-uidist***.*"> <LogicalName>%(RecursiveDir)%(FileName)%(Extension)</LogicalName> <InProject>false</InProject> </EmbeddedResource> </ItemGroup>
根據路徑檢視,swagger-ui下是空白的。將從其他地方找到的或者從反編譯檔案裡整理出來的檔案放到該目錄下,並將swagger-ui作為依賴項,重新編譯專案後swagger頁面載入資原始檔就正常了。(如果有遇到依舊找不到資原始檔的情況,重新再新增一次依賴項編譯專案即可)
接下來就可以開始偵錯了,經過一番波折,最終將元凶定位到了SwaggerGenerator中GetSwagger方法裡獲取paths這個地方,實際上就是在使用CreatePathItem的時候耗時過久
var paths = GetApiDescriptionsFor(apiVersion) .Where(apiDesc => !(_options.IgnoreObsoleteActions && apiDesc.IsObsolete())) .OrderBy(_options.GroupingKeySelector, _options.GroupingKeyComparer) .GroupBy(apiDesc => apiDesc.RelativePathSansQueryString()) .ToDictionary(group => "/" + group.Key, group => CreatePathItem(group, schemaRegistry));
剛開始嘗試用多執行緒的方式進行處理,儘管確實能夠縮短獲取json資料的時間,但依舊有兩個問題:
執行緒不安全,時不時頁面會報錯即使能快速返回json資料,頁面渲染耗慢的問題依舊未解決。正如前面我們的專案中GetSwagger是使用到快取的,在重新重新整理swagger時,依舊存在卡慢問題。
優化swagger載入,需要同時考慮到前端渲染頁面以及後端梳理json資料所導致的頁面載入慢問題。有什麼好的辦法麼?swashbuckle core版本是支援分組的,但是專案使用的Framework版本不支援,既然不支援,就直接改造原始碼,按控制器分組,說幹就幹:
找到HttpConfigurationExtensions類的EnableSwagger方法,這個方法用來設定路由
public static SwaggerEnabledConfiguration EnableSwagger( this HttpConfiguration httpConfig, string routeTemplate, Action<SwaggerDocsConfig> configure = null) { var config = new SwaggerDocsConfig(); if (configure != null) configure(config); httpConfig.Routes.MapHttpRoute( name: "swagger_docs" + routeTemplate, routeTemplate: routeTemplate, defaults: null, constraints: new { apiVersion = @".+" }, handler: new SwaggerDocsHandler(config) ); //設定控制器路由 string controllRouteTemplate=DefaultRouteTemplate+"/{controller}"; httpConfig.Routes.MapHttpRoute( name: "swagger_docs" + controllRouteTemplate, routeTemplate: controllRouteTemplate, defaults: null, constraints: new { apiVersion = @".+" }, handler: new SwaggerDocsHandler(config) ); return new SwaggerEnabledConfiguration( httpConfig, config.GetRootUrl, config.GetApiVersions().Select(version => routeTemplate.Replace("{apiVersion}", version))); }
接下來找到SwaggerDocsHandler類,修改SendAsync方法,獲取controller,並將controller傳遞到GetSwagger中
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) { var swaggerProvider = _config.GetSwaggerProvider(request); var rootUrl = _config.GetRootUrl(request); var apiVersion = request.GetRouteData().Values["apiVersion"].ToString(); var controller = request.GetRouteData().Values["controller"]?.ToString(); if (string.IsNullOrEmpty(controller)) { controller = "Account"; } try { var swaggerDoc = swaggerProvider.GetSwagger(rootUrl, apiVersion, controller); var content = ContentFor(request, swaggerDoc); return TaskFor(new HttpResponseMessage { Content = content }); } catch (UnknownApiVersion ex) { return TaskFor(request.CreateErrorResponse(HttpStatusCode.NotFound, ex)); } }
相對應的修改ISwagger介面,以及介面的實現類SwaggerGenerator,增加按Controller篩選
public interface ISwaggerProvider { SwaggerDocument GetSwagger(string rootUrl, string apiVersion,string controller); }
SwaggerGenerator的GetSwagger修改:
var temps = GetApiDescriptionsFor(apiVersion) .Where(apiDesc => !(_options.IgnoreObsoleteActions && apiDesc.IsObsolete())); if (string.IsNullOrEmpty(controller) == false) { temps = temps.Where(apiDesc => apiDesc.ActionDescriptor.ControllerDescriptor.ControllerName.ToLower() == controller.ToLower()); } var paths = temps .OrderBy(_options.GroupingKeySelector, _options.GroupingKeyComparer) .GroupBy(apiDesc => apiDesc.RelativePathSansQueryString()) .ToDictionary(group => "/" + group.Key, group => CreatePathItem(group, schemaRegistry));
自己專案中關於ISwagger實現也要修改,然後開始重新編譯自己的專案,重新開啟swagger頁面,頁面在後端編譯後第一次開啟也非常迅速。預設開啟的是Account控制器下的介面,如果切換到其他控制器下的介面只需要在url後加入對應的/Controller
以上我們已經把頁面的載入慢的問題解決了,但在切換控制器上是否過於麻煩,能不能提升前端開發人員的使用體驗,提供一個下拉選單選擇是不是更好呢?繼續幹!
找到原始碼目錄下的SwaggerUiCustomAssetsIndex.html檔案,新增一個id為select_baseUrl的select下拉選擇框,並將input_baseurl輸入框隱藏
修改swagger-ui-js下的window.SwaggerUi的render方法(要記得將index.html中的swagger-ui-min-js的參照改為swagger-ui-js)加入填充下拉資料的js程式碼以及新增下拉框觸發事件
找到SwaggerUi.Views.HeaderView,新增下拉事件
重新編譯後,重新整理頁面試試效果,可以下拉選擇分組
到此這篇關於Swagger優化的文章就介紹到這了,更多相關Swagger優化實戰內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45