Swagger UI导致​​产生除JSON以外的内容类型的操作的HTTP 406不可接受的响应

ras*_*orp 5 java rest jersey swagger swagger-ui

我有一个发布于Jersey并由Swagger记录的REST API,也有一个使用该API的Swagger UI安装。

我几乎所有的操作都会产生application / json并按预期工作,除了一个GET操作会产生:'text / plain; charset = utf-8'

当我尝试从Swagger UI调用服务时,服务器会记录一个javax.ws.rs.NotAcceptableException并返回406响应。如果我从REST客户端调用相同的服务,则它将按预期工作。

@GET
@Path("/text")
@Produces(MediaType.TEXT_PLAIN + ";charset=utf-8")
@ApiOperation(value= "Return text")
public Response getText(@QueryParam("user") String user) {
    return Response.ok(textService.getTextForUser(user)).build();
}
Run Code Online (Sandbox Code Playgroud)

如果我更改为@Produces(MediaType.APPLICATION_JSON +“; charset = utf-8”),则可以正常使用,但我不想设置错误的内容类型。

问题似乎是Swagger UI错误地将Accept标头设置为application / json,这可以通过观察请求来看出:

GET /supertext/text?user=1
...
Accept: application/json
Run Code Online (Sandbox Code Playgroud)

使用其余客户端时,Accept标头为:

GET /supertext/text?user=1
...
Accept: */*
Run Code Online (Sandbox Code Playgroud)

为什么Swagger UI无法正确设置Accept标头?

可以配置吗?

ras*_*orp 5

看起来,当 swagger ui 发现 @Produces 注释包含单个值时,它会将接受头设置为 application/json ,否则它会在 ui 中呈现一个下拉列表以从可用的内容类型中进行选择。

在 swagger-ui.js 中:

opts.responseContentType = $("div select[name=responseContentType]", $(this.el)).val();
Run Code Online (Sandbox Code Playgroud)

当下拉列表不存在时,该属性变为未定义。

稍后在代码中,如果属性为 null 或未定义,则响应内容类型将设置为 application/json:

在 swagger.js 中:

if (this.type === "POST" || this.type === "GET" || this.type === "PATCH") {
    if (this.opts.responseContentType) {
      responseContentType = this.opts.responseContentType;
    } else {
      responseContentType = "application/json";
    }
  }
Run Code Online (Sandbox Code Playgroud)

因此,我的解决方案是修改 swagger-ui.js 中的代码,通过探索 Produces 数组并选择第一个元素作为响应内容类型来确保设置正确的内容类型:

在 swagger-ui.js 中替换以下行:

opts.responseContentType = $("div select[name=responseContentType]", $(this.el)).val();
Run Code Online (Sandbox Code Playgroud)

和:

if($("div select[name=responseContentType]", $(this.el)).val() === undefined) { 
    opts.responseContentType = opts.parent.model.produces[0];
}

else {
    opts.responseContentType = $("div select[name=responseContentType]", $(this.el)).val();
}
Run Code Online (Sandbox Code Playgroud)