新版本 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 ...
随机推荐
- 使用redis来调用iptables,封禁恶意IP
话不多说,通常大多数站点都会有被薅羊毛的情况,防护无非也就是业务层做处理,短时内不再响应恶意请求啦.虽然不响应了,可还是会消耗资源的,比如我要从数据库(当然也可能是内存数据库)去查询下,你是不是恶意的 ...
- IP地址的获取
//ip地址的获取:非原创,之前在其他地方看到,拿过来备份下: public static String getIPAddress(HttpServletRequest request) { Stri ...
- SVN合并分支提示不是祖先关系
开发:dev 测试:test 开发完成后,需要合并到test然后部署,进入测试. F:主干 合并到那里,那里就是主干(要合并到的分支)[起始] T:分支 从那里合并那里就是分支[结束] 备注:需要精确 ...
- 【Python】数字与运算符
数据类型与运算符 数字 / 浮点除 // 整数除 ** 乘方 多种混合类型运算数的运算会把整数转换为浮点数 除了 int 和 float,Python也支持其他类型的数字,例如 Decimal 或者 ...
- 基于Huggingface使用BERT进行文本分类的fine-tuning
随着BERT大火之后,很多BERT的变种,这里借用Huggingface工具来简单实现一个文本分类,从而进一步通过Huggingface来认识BERT的工程上的实现方法. 1.load data tr ...
- 给Python IDLE添加行号显示
转载:https://blog.csdn.net/howard2005/article/details/104112297 文章目录一.引出问题1.Spyder编辑Python程序能显示行号2.Pyt ...
- 更改MySQL 5.7的数据库的存储位置
操作系统:Windows 10 x64 MySQL安装包版本:mysql-installer-community-5.7.17.0 参考:MySQL 5.7版本的安装使用详细教程+更改数据库data的 ...
- 洛谷比赛 「EZEC」 Round 4
洛谷比赛 「EZEC」 Round 4 T1 zrmpaul Loves Array 题目描述 小 Z 有一个下标从 \(1\) 开始并且长度为 \(n\) 的序列,初始时下标为 \(i\) 位置的数 ...
- 这就是小学生也会用的四则计算练习APP吗?- by软工结对编程项目作业
结对编程项目 软件工程 这就是链接 作业要求 这就是链接 作业目标 熟悉在未结对情况下如何结对开发项目 Github与合作者 合作者(学号): 区德明:318005422 虚左以待 Github链接: ...
- 空间视频和GIS
摘要. GIS的空间数据基本单位表示通常是根据 点,线和面.但是,另一种类型的空间数据正在变得越来越频繁 捕获的是视频,但在GIS中却被很大程度上忽略了.数字录像时 是现代社会中常见的一种媒介,包含多 ...