Swashbuckle/NSwag:关于swagger页面中接口地址不方便复制问题的一个解决办法
之前有博友提到swagger页面的地址不好复制,我也有这种感觉,最近又有朋友跟我抱怨这个,所以今天花了点时间来看看有什么解决办法。
原先,在一个swagger页面,如果想复制,当鼠标放在一个接口项上点击后,是无法进行选择的,因为点击表示打开这个选项卡!
但是我们可以点击其它空白区域,然后进行选择是可以的:
但是复制后,你会发现,前面的请求方法也会被复制,如果从后面拖选,那么注释就会被选中。。。
通过F12发现,这块地址其实是在一个span里面:
所以就有了一个想法,又能方便复制,又不影响现有功能,一个很好的办法就是让它变成可编辑,而我们的html元素就有个contenteditable属性,表示是否可编辑。
我本来想看看有没有事件委托之类的,可以在让我们通过回调手动的添加这个属性,但是结果很遗憾。
不过,通过查看index.html页面的源码,以及通过断点调试发现,swaggerUI其实是通过React来渲染的,正巧swagger将React相关函数等整合到一个ui对象中,然后将它挂到了window下:
在控制台输出这个ui对象,发现里面的React对象有一个createElement函数,于是一个邪恶的想法来了:覆盖这个createElement函数,注入将页面所有的span设置成contenteditable!
于是便有了这么一段代码:
window.addEventListener('load', function () {
setTimeout(() => {
let createElement = window.ui.React.createElement
window.ui.React.createElement = function () {
let array = Array.from(arguments)
if (array.length == 3) {
if (array[0] == 'span' && !array[1]) {
array[1] = { contentEditable: true }
}
}
let ele = createElement(...array)
return ele
}
})
})
接下来就是把这段代码注入了,巧的是Swashbuckle/NSwag都支持注入js代码,于是便有了下面两个拓展方法:
如果是Swashbuckle:
/// <summary>
/// 设置Span为可编辑
/// </summary>
/// <param name="swaggerUIOptions"></param>
public static void SetSpanEditable(this Swashbuckle.AspNetCore.SwaggerUI.SwaggerUIOptions swaggerUIOptions)
{
StringBuilder stringBuilder = new StringBuilder(swaggerUIOptions.HeadContent);
stringBuilder.Append(@"
<script type='text/javascript'>
window.addEventListener('load', function () {
setTimeout(() => {
let createElement = window.ui.React.createElement
ui.React.createElement = function () {
let array = Array.from(arguments)
if (array.length == 3) {
if (array[0] == 'span' && !array[1]) {
array[1] = { contentEditable: true }
}
}
let ele = createElement(...array)
return ele
}
})
})
</script>");
swaggerUIOptions.HeadContent = stringBuilder.ToString();
}
使用的时候:
app.UseSwagger();
app.UseSwaggerUI(options =>
{
//其它代码
options.SetSpanEditable();
});
如果是NSwag:
/// <summary>
/// 设置Span为可编辑
/// </summary>
/// <param name="swaggerUIOptions"></param>
public static void SetSpanEditable(this NSwag.AspNetCore.SwaggerUi3Settings swaggerUIOptions)
{
StringBuilder stringBuilder = new StringBuilder(swaggerUIOptions.CustomHeadContent);
stringBuilder.Append(@"
<script type='text/javascript'>
window.addEventListener('load', function () {
setTimeout(() => {
let createElement = window.ui.React.createElement
ui.React.createElement = function () {
let array = Array.from(arguments)
if (array.length == 3) {
if (array[0] == 'span' && !array[1]) {
array[1] = { contentEditable: true }
}
}
let ele = createElement(...array)
return ele
}
})
})
</script>");
swaggerUIOptions.CustomHeadContent = stringBuilder.ToString();
}
使用的时候:
app.UseOpenApi();
app.UseSwaggerUi3(options =>
{
//其它代码
options.SetSpanEditable();
});
运行后,点击接口地址,然后ctrl+A全选,ctrl+C完成复制了:
注:虽然这个方法可以方便复制接口,但是因为可编辑,可能会导致某些意想不到的问题