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完成复制了:

  

 

  注:虽然这个方法可以方便复制接口,但是因为可编辑,可能会导致某些意想不到的问题

 

posted @ 2022-05-18 18:42  没有星星的夏季  阅读(1388)  评论(0编辑  收藏  举报