新版本 swagger 组件中 Servers 的 坑
新版本 Swashbuckle swagger 组件中 Servers 的 坑
Intro
上周做了公司的项目升级,从 2.2 更新到 3.1, swagger 直接更新到了最新,swagger 用的组件是 Swashbuckle.AspNetCore
,然后遇到一个 swagger 的问题,
在本地测试是没问题的,但是部署在测试环境之后就会有问题,主要是 swagger 界面会多一个 servers 的选项,可能会导致 swagger 不能正常使用,下面详细介绍一下
Swagger "bug" reproduce
大概的问题是这样的,在本地环境是好的,在测试环境部署是有问题,测试环境部署之后的 swagger 界面大致如下:
很明显这个 servers 是有问题的,我们实际访问的地址是 https://testserver/swagger
这样的地址,但是 swagger 内部拼出来的 server 地址和实际访问的地址是不符的,swagger 生成的 open api 文档里也会有一个 servers 的属性,示例如下:
这会导致我们使用 swagger 调试 API 的时候会走一个错误的 server 地址,实际请求的地址是 sever 地址加上 api path,可以看一个示例
Dig the Source
Swashbuckle.AspNetCore
是开源的,我们就是扒一扒它的实现源码吧,我们用的是 5.6.3 版本,直接看 5.6.3 tag 对应的代码,可以找到 swagger 的中间件
在这里我们可以看到,再返回给客户端之前 open api 文档响应之前我们是可以看到,是会经过 PreSerializeFilters
处理的,我们再详细看一下 swaggerProvider.GetSwagger
的实现
实现代码在这里(可以通过服务注册找到对应的实现,也可以直接找对应接口的实现)
二者结合来看,servers 会根据用户请求来获取一个 server 地址,而当有 X-Forwarded-Host
请求头的时候如果没有按照 swagger 指定的规则这样进行请求头的转发就会导致有问题,而我们的测试环境也正是因为如此,测试环境有一层 LB,经过 LB 转发了 X-Forwarded-Host
和 X-Forwarded-Proto
请求头,但是没有转发 X-Forwarded-Port
所以经过 swagger 的处理之后,就从 https://testserver
变成了 https://testserver:80
这样
private string GetHostOrNullFromRequest(HttpRequest request)
{
if (!request.Headers.TryGetValue("X-Forwarded-Host", out StringValues forwardedHost))
return null;
var hostBuilder = new UriBuilder($"http://{forwardedHost[0]}");
if (request.Headers.TryGetValue("X-Forwarded-Proto", out StringValues forwardedProto))
hostBuilder.Scheme = forwardedProto[0];
if (request.Headers.TryGetValue("X-Forwarded-Port", out StringValues forwardedPort))
hostBuilder.Port = int.Parse(forwardedPort[0]);
return hostBuilder.Uri.ToString().Trim('/');
}
private string GetBasePathOrNullFromRequest(HttpRequest request)
{
var pathBuilder = new StringBuilder();
if (request.Headers.TryGetValue("X-Forwarded-Prefix", out StringValues forwardedPrefix))
pathBuilder.Append(forwardedPrefix[0].TrimEnd('/'));
if (request.PathBase.HasValue)
pathBuilder.Append(request.PathBase.Value.TrimEnd('/'));
return (pathBuilder.Length > 0)
? pathBuilder.ToString()
: null;
}
解决方案
从上面的源码中基本就可以分析出问题的原因来,解决的办法我觉得有下面几种:
- LB 转发的时候带上
X-Forwarded-Port
请求头,转发原始请求的端口号(需要 LB 转发自己能够控制,我们如果要配置还需要让 DevOps 的童鞋帮忙弄,如果完全是自己控制的就比较方便【推荐】) - 在使用 Swagger 中间件之前把
X-Forwarded-Port
请求头设置为443
(不够灵活,如果访问 LB 是 http 或者有特别的端口号就会有问题) - 在使用 swagger 中间件之前把
X-Forwarded-Host
请求头移除掉,这样就不会有 servers 这个属性了(感觉不够优雅) - 注册一个
PreSerializeFilter
把 Servers 清空,实现代码如下(【推荐】,没有 servers 属性的时候完全按请求 swagger 的 baseUrl 来作为 api 的前缀,示例代码如下)
app.UseSwagger(c =>
{
c.PreSerializeFilters.Add((doc, _) =>
{
doc.Servers?.Clear();
});
});
更新之后就没有 servers 属性了,和之前的版本保持一致了
More
我们使用的是 5.6.3 版本,应该从 5.6.0 开始都有这个问题,如果遇到了这个问题不要慌哈,参考上面的解决方案即可
我觉得 swagger 这样的实现方式不太友好,更好的实现应该结合微软的 ForwardHeaders
中间件来实现,Swagger 组件作者表示已经有计划,打算在 6.0 的时候更新结合微软的中间件来实现,详细可以参考 Github 上的 Issue https://github.com/domaindrivendev/Swashbuckle.AspNetCore/issues/1814
Reference
- https://github.com/domaindrivendev/Swashbuckle.AspNetCore
- https://github.com/domaindrivendev/Swashbuckle.AspNetCore/blob/v5.6.3/src/Swashbuckle.AspNetCore.Swagger/SwaggerMiddleware.cs
- https://github.com/domaindrivendev/Swashbuckle.AspNetCore/blob/v5.6.3/src/Swashbuckle.AspNetCore.SwaggerGen/SwaggerGenerator/SwaggerGenerator.cs#L31
- https://github.com/domaindrivendev/Swashbuckle.AspNetCore/issues/1814
新版本 swagger 组件中 Servers 的 坑的更多相关文章
- Asp.Net Core WebApi中接入Swagger组件(初级)
开发WebApi时通常需要为调用我们Api的客户端提供说明文档.Swagger便是为此而存在的,能够提供在线调用.调试的功能和API文档界面. 环境介绍:Asp.Net Core WebApi + S ...
- 在vue组件中style scoped中遇到的坑
在uve组件中我们我们经常需要给style添加scoped来使得当前样式只作用于当前组件的节点.添加scoped之后,实际上vue在背后做的工作是将当前组件的节点添加一个像data-v-1233这样唯 ...
- vue js 在组件中对数组使用splice() 遇到的坑。。。
遇到的问题: 用el-dialog写了个子组件 要实现在子组件中增删数据 点击确定后把值返回给父组件 父组件在每次点开子组件时都会把自己的值传进去. //父组件传值 this.$refs.transf ...
- 微信小程序中的自定义组件 以及 相关的坑
Step1 我们初始化一个小程序(本示例基础版本库为 1.7 ),删掉里面的示例代码,并新建一个 components 文件夹,用于存放我们以后开发中的所用组件,今天我们的目的是实现一个 首页 组件, ...
- vue 组件中数组的更新
今天写项目时遇到的问题,瞬间就卡在那了 来还原一下: parent.vue: <template> <div> <button @click="change&q ...
- angular2的ElementRef在组件中获取不到
angular2的ElementRef在组件中获取不到 angular2不推荐操作dom,但是实际应用中不可避免的需要使用到dom操作,怎么操作,官方文档提供了一系列api(ElementRef,Vi ...
- vue中遇到的坑!!!!!
一 .vue安装的坑 报错时的常见问题 1.cnpm install 模块名 –save-dev(关于环境的,表现为npm run dev 启动不了)cnpm install 模块名 –save(关于 ...
- 总结微信小程序开发中遇到的坑
总结微信小程序开发中遇到的坑,一些坑你得一个一个的跳啊,/(ㄒoㄒ)/~~ 1,页面跳转和参数传递实例 首先说一下我遇到的需求有一个我的消息页面,里面的数据都是后端返回的,返回的数据大致如下,有一个是 ...
- vue中的css作用域、vue中的scoped坑点
一.css作用域 之前一直很困扰css的作用域问题,即使是模块化编程下,在对应的模块的js中import css进来,这个css仍然是全局的.导致在css中需要加上对应模块的html的id/class ...
随机推荐
- 单元测试框架怎么搭?快来看看新版Junit5的这些神奇之处吧!
为什么使用JUnit5 JUnit4被广泛使用,但是许多场景下使用起来语法较为繁琐,JUnit5中支持lambda表达式,语法简单且代码不冗余. JUnit5易扩展,包容性强,可以接入其他的测试引擎. ...
- GAN的理论 Theory behind GAN
任务:想要找到一个高维空间中的分布 P_data(x),要在目标类别的区域,采样的概率是高的:在那个区域之外,probability是低的.但这个P_data(x)分布的具体形式(pdf)是不知道的, ...
- 星涛:采用java递归复制文件夹
package com.botao; import java.io.*; /** * @author cbt28 */ public class FileUtil { public static St ...
- CentOS之—双网卡双IP双网关配置
转载请注明出处:http://blog.csdn.net/l1028386804/article/details/77487639 一.配置讲解 1.配置DNS 修改对应网卡的DNS的配置文件 # v ...
- 史上最全Python快速入门教程,满满都是干货
Python是面向对象,高级语言,解释,动态和多用途编程语言.Python易于学习,而且功能强大,功能多样的脚本语言使其对应用程序开发具有吸引力.Python的语法和动态类型具有其解释性质,使其成为许 ...
- MySQL数据库的完全备份与恢复
前言 在生产环境中,数据的安全性是至关重要的,任何数据的丢失都可能产生严重的后果,正确的数据库操作是实际环境下不可缺少的. 一.数据库备份的分类 1.1 从物理与逻辑的角度,备份的分类 物理备份:对数 ...
- 怎么快速从产品助理/初级 PM 成长为高级 PM?
一般想成为一枚产品经理的同学,如果没有经过系统的学习,都是从产品专员/助理开始做起的~ 那要想快速从产品助理/初级 PM 成长为高级 PM,以下这几点必不可少 直接上干货~ 全文篇幅较长,可以点赞收藏 ...
- Hello World -- 第一篇博客 -- 活着的意义
今年注定是不寻常的一年,因为技术,接触了许多大牛.通过一篇篇博文,看到了大牛们勤奋好学.孜孜不倦的精神,于是决定也开个博客,向大牛学习. 博客开了,写点什么呢?奈何肚子里墨水不多,吐出来也多是白沫,不 ...
- 2017年 实验四 B2C模拟实验
实验四 B2C模拟实验 [实验目的] 掌握网上购物的基本流程和B2C平台的运营 [实验条件] ⑴.个人计算机一台 ⑵.计算机通过局域网形式接入互联网. (3).奥派电子商 ...
- 多测师讲解requests __中_高级讲师肖sir
(1)生成报告 import unittest #导入单元测试框架 import requests #导入接口库 import time # #时间戳,导入time模块 from api.HTMLTe ...