关于swagger:Swagger异常定位纪实是用的不对还是Swagger本身设计问题

92次阅读

共计 2573 个字符,预计需要花费 7 分钟才能阅读完成。

前言

swagger ui 是一个采纳注解驱动的接口文档工具,目前已反对规范的 open api v3 标准协定,所以不仅能够在 java 我的项目里应用,每个语言都有相应的 open api 实现。我的项目集成 swagger 后,能够生成导出 open api v3 格式化的元数据集,有了这个接口元数据,你能够在任何反对 v3 协定的 ui 上展现你的 api 信息。在前后端拆散的我的项目中,swagger ui 的呈现,大大提高了前后端联调的效率。swagger ui 在解析注解标注的元数据信息时,特地场景下会抛异样,而且抛的异样没有直观的有价值的异样信息,所以深刻的 debug 了一番,尽管最初问题解决很简略,然而过程十分波折。故将 bug 定位过程记录在此。

  • 影响的 Swagger 版本:1.5.x
  • Swagger core:https://github.com/swagger-api/swagger-core
  • OpenApi v3 标准:https://github.com/OAI/versions/3.0.0.md

异样信息


这个异样只会在加载 swagger-ui 的页面时会抛出,每次刷新页面,获取一次 api 接口就会触发一次异样。

异样剖析

@JsonProperty("x-example")
public Object getExample() {if (example == null) {return null;}
    try {if (BaseIntegerProperty.TYPE.equals(type)) {return Long.valueOf(example);
 } else if (DecimalProperty.TYPE.equals(type)) {return Double.valueOf(example);
 } else if (BooleanProperty.TYPE.equals(type)) {if ("true".equalsIgnoreCase(example) || "false".equalsIgnoreCase(defaultValue)) {return Boolean.valueOf(example);
 }
        }
    } catch (NumberFormatException e) {LOGGER.warn(String.format("Illegal DefaultValue %s for parameter type %s", defaultValue, type), e);
 }
    return example;
}

如上是异样相干的代码。从异样信息表象来看,是一个强转导致的问题,代码试图将一个空的字符串转换成数值类型导致异样抛出。并且是 getExample 时抛出的异样,这里须要理解 swagger ui 的加载过程和基础架构能力间接定位。swagger 中的 example 是为了在生成的 api doc 中,给出相干字段的调用示例,并在触发接口调用时,默认主动填充 example 的值。这里显然是哪个中央的 example 设置不合理导致的异样。那么,接下来要做的就是找到这个空字符串的原始代码。

debug 找到实在起因

借助 IDEA 的 debug 性能,点击异样前面的 create breakpoint,在触发异样的中央打上断点。触发异样,进入断点,获取到了要害信息

一个被形容为 app id 的字段,用这个信息全局搜寻,失去如下的后果:

有三个相干的 Model 实体,首先,这三个 Model 的 appId 字段都没有设置过 example 属性,所以,到这一步,能够先下一个小的论断,不是咱们设置的 example 导致的问题,默认在不设置的状况下,example 的默认值就是空字符串。而后必定只有其中一个有问题,因为异样只会触发一次。在不晓得后果状况下,顺次对这三个 Model 的 appId 字段加上正确的 example 形容,经测试,只有 GetAppBannerRequestDTO 加上时,异样才隐没,罪魁祸首就是它了。然而,为什么呢?其余两个 Model 为啥就没有问题呢?在博主穿插测验后,发现了最终的起因。

论断及注意事项

当 Model 作用于申请的接管参数时,并且申请的类型为 GET,那么 Swagger Ui 会主动收集 Model 所有属性的 examole 参数,因为这个参数是字符串类型,所以会做一个类型转换动作。当字段类型为数值类型,又有没手动设置 example 的值,那么 Swagger 框架拿到的是个空字符串,强转空字符串就抛异样了。而如果申请是 POST,就不会触发这段逻辑,所以同为携带数值类型 DTO 的 ImgReplaceRequestDTO 没有问题。如果不是接管参数,作为响应参数,也不会触发这段逻辑,故而 AppBannerResponseVO 也就没有问题了。所以,须要留神的就是当 DTO 作用于 GET 申请的接管参数时,切记给所有的数值类型加上正确的 example 属性

后记

博主认为这里属于一个设计缺点,而不是咱们的应用问题。在获取 example 的逻辑里,第一段代码就判断了 example 是否为 null。这表明了 example 有可能为空,然而默认值却设置了一个空字符串。代表不手动将 example 设置为 null,这段判 null 返回的逻辑就永远跑不到,而且没人会这么做,手动给 example 设置为 null。况且,在触发异样的这种场景下,框架不能强制使用者设置 example 这种操作。在 github 仓库追踪这块代码发现,目前 Swagger ui 曾经迈入了 3.x 版本,全面基于 open api v3 协定标准设计。所以,这部分代码齐全不一样了。而存档的 1.5x 版本这个问题仍旧。

上面是 3.x 的解决形式,尽管 example 的默认值还是“”。然而通过 NotBlank 判断了下,所以不会触发异样了

为啥不间接降级 3.x?

3.x 版本既然曾经修复了,为啥不间接降级到 3.x 版本呢?可能有人会有这个疑难。Swagger3.x 版本属于一个大跨度的迭代版本,和之前的版本齐全不兼容,3.x 次要面向了 open api v3 标准协定设计实现,注解实体等模型都是一一对应的。而在这个版本之前的 1.5x 系列版本是 Swagger 本人设计的 api 模型。所以代码层下面齐全不兼容,降级的工作量会十分大。不过,新我的项目还是举荐应用 3.x 版本,这个版本的 api 数据更通用。能够依据 api 的数据生成各种语言的客户端包。就像 proto 生成客户端包一样。

正文完
 0