【问题标题】:Swagger Codegen - Content Type for GET not getting set in Spring-MVC generatedSwagger Codegen - GET 的内容类型未在 Spring-MVC 生成
【发布时间】:2016-02-04 08:16:02
【问题描述】:

从 swagger.io 编辑器页面下载 Swagger Pet Store (Simple) 并做了一个 mvn jetty:run

在 Chrome 上打开 DevTools 并执行 GET 时,我没有看到设置了标头 Content-Type 字段。

这是在 GET /pets{id}

【问题讨论】:

  • 图像中的所有标题有点难以看到。但是您在 HTML 响应中将内容类型设置为“META”标签,而不是 HTTP 标头,这可能是您收到错误页面这一事实的副作用。如果没有 REQUEST 标头,很难确定,但我认为它是在说“你要求 JSON,我不知道那是什么”
  • 我的意思是 curl 的 REQUEST 标头。 DevTools 说“接受应用程序/xml”
  • 是的,但是 devtools 请求标头根本没有设置内容类型。我发布此示例的原因是因为在我的 spring 控制器上的真实代码中,我得到:{"timestamp":1446597153755,"status":400,"error":"Bad Request","exception":"org.springframework. web.HttpMediaTypeNotSupportedException","message":"不支持内容类型'null'","path":"/hacker/api/mef/sca/v1/SCA_ETH_FDFr_EC/5"}
  • 那是因为 REQUEST 中的标头不是“Content-Type”,而是“Accept”。 RESPONSE 具有“Content-Type”,并且 curl 输出在 META 标记中指定,而不是作为 HTTP 标头(未显示)。尝试在 curl 示例中使用“Accept: application/xml”。我怀疑 MIME 类型映射失败,并且 DevTools 显示 chrome 请求 application/xml
  • Header 请求中的 Content-Type 和 Accept 意味着 2 个不同的东西。在这种情况下,Content-Type 不存在,因此为空。 curl -X GET --header "Accept: application/json" --header "Content-Type: application/json" "xxxx" 不抱怨

标签: swagger swagger-ui springfox


【解决方案1】:

http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html

14.17 内容类型

Content-Type entity-header 字段指明了媒体类型 实体主体发送给接收者,或者在 HEAD 方法的情况下, 如果请求是 GET,将发送的媒体类型。 Content-Type = "Content-Type" ":" 媒体类型

Content-Type 是 request 上下文中的无意义标头。 由于请求没有正文,因此对于“GET”来说更是如此。

如果您可以为 Chrome 和 curl 发布请求和响应标头和正文,我也许可以为您解决这个问题。

话虽如此,环顾 StackOverflow 很快就告诉我,Spring 可能出于与内容编码无关的多种原因引发此错误。例如(例如)您尝试序列化的对象缺少无参数构造函数。

您是否设置了任何日志记录来跟踪 InnerExceptions 和堆栈以查看基本错误是什么?

这是 Spring 对我的应用程序(而不是 petstore)所做的事情。你也想要我的应用的 swagger ui 页面的屏幕截图吗?

感谢您关注这位罗杰。

2015-11-04 18:32:13.977 DEBUG 32416 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : DispatcherServlet with name 'dispatcherServlet' processing GET request for [/hacker/api/mef/sca/v1/SCA_ETH_FDFr_EC/5]
2015-11-04 18:32:13.977 DEBUG 32416 --- [nio-8080-exec-1] s.w.s.m.m.a.RequestMappingHandlerMapping : Looking up handler method for path /api/mef/sca/v1/SCA_ETH_FDFr_EC/5
2015-11-04 18:32:13.980 DEBUG 32416 --- [nio-8080-exec-1] .m.m.a.ExceptionHandlerExceptionResolver : Resolving exception from handler [null]: org.springframework.web.HttpMediaTypeNotSupportedException: Content type 'null' not supported
2015-11-04 18:32:13.980 DEBUG 32416 --- [nio-8080-exec-1] .m.m.a.ExceptionHandlerExceptionResolver : Invoking @ExceptionHandler method: public void com.ciena.sca.exception.ApiExceptionHandler.handleOtherErrors(java.lang.Exception,javax.servlet.http.HttpServletResponse)
2015-11-04 18:32:13.980 ERROR 32416 --- [nio-8080-exec-1] c.c.sca.exception.ApiExceptionHandler    : Content type 'null' not supported
org.springframework.web.HttpMediaTypeNotSupportedException: Content type 'null' not supported
    at org.springframework.web.servlet.mvc.method.RequestMappingInfoHandlerMapping.handleNoMatch(RequestMappingInfoHandlerMapping.java:231)
    at org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.lookupHandlerMethod(AbstractHandlerMethodMapping.java:349)
    at org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.getHandlerInternal(AbstractHandlerMethodMapping.java:296)
    at org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.getHandlerInternal(AbstractHandlerMethodMapping.java:56)
    at org.springframework.web.servlet.handler.AbstractHandlerMapping.getHandler(AbstractHandlerMapping.java:299)
    at org.springframework.web.servlet.DispatcherServlet.getHandler(DispatcherServlet.java:1120)
    at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:932)
    at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:893)
    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:967)
    at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:858)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:622)
    at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:843)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:729)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:291)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
    at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
    at org.springframework.boot.actuate.autoconfigure.EndpointWebMvcAutoConfiguration$ApplicationContextHeaderFilter.doFilterInternal(EndpointWebMvcAutoConfiguration.java:299)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
    at org.springframework.boot.actuate.trace.WebRequestTraceFilter.doFilterInternal(WebRequestTraceFilter.java:102)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
    at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:85)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
    at org.springframework.boot.actuate.autoconfigure.MetricsFilter.doFilterInternal(MetricsFilter.java:76)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:217)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:106)
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:502)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:142)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:88)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:518)
    at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1091)
    at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:673)
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1500)
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1456)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
    at java.lang.Thread.run(Thread.java:745)
2015-11-04 18:32:13.982 DEBUG 32416 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : Null ModelAndView returned to DispatcherServlet with name 'dispatcherServlet': assuming HandlerAdapter completed request handling
2015-11-04 18:32:13.982 DEBUG 32416 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : Successfully completed request
2015-11-04 18:32:13.983 DEBUG 32416 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : DispatcherServlet with name 'dispatcherServlet' processing GET request for [/hacker/error]
2015-11-04 18:32:13.983 DEBUG 32416 --- [nio-8080-exec-1] s.w.s.m.m.a.RequestMappingHandlerMapping : Looking up handler method for path /error
2015-11-04 18:32:13.983 DEBUG 32416 --- [nio-8080-exec-1] s.w.s.m.m.a.RequestMappingHandlerMapping : Returning handler method [public org.springframework.http.ResponseEntity<java.util.Map<java.lang.String, java.lang.Object>> org.springframework.boot.autoconfigure.web.BasicErrorController.error(javax.servlet.http.HttpServletRequest)]
2015-11-04 18:32:13.983 DEBUG 32416 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : Last-Modified value for [/hacker/error] is: -1
2015-11-04 18:32:13.985 DEBUG 32416 --- [nio-8080-exec-1] o.s.w.s.m.m.a.HttpEntityMethodProcessor  : Written [{timestamp=Wed Nov 04 18:32:13 EST 2015, status=400, error=Bad Request, exception=org.springframework.web.HttpMediaTypeNotSupportedException, message=Content type 'null' not supported, path=/hacker/api/mef/sca/v1/SCA_ETH_FDFr_EC/5}] as "application/json;charset=UTF-8" using [org.springframework.http.converter.json.MappingJackson2HttpMessageConverter@2ed7a433]
2015-11-04 18:32:13.985 DEBUG 32416 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : Null ModelAndView returned to DispatcherServlet with name 'dispatcherServlet': assuming HandlerAdapter completed request handling
2015-11-04 18:32:13.985 DEBUG 32416 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : Successfully completed request

【讨论】:

  • 好的。前 3 行读给我听 1. 开始处理。 2. 查找此 URL 的处理程序。 3. 失败,因为我没有得到处理程序的映射。所以我会说 url 解析/路由是问题所在。对此无能为力,因为它将是特定于应用程序的,您需要开始披露潜在的安全敏感细节。
【解决方案2】:

好的,感谢github上swagger codegen项目上的wing328,找到了这个问题的根本原因。

事实证明,在我们的 yaml 定义文件的顶部,我们有:

消耗: - 应用程序/json

这会导致所有生成的控制器方法在 content-type 上期望 application/json。这会破坏 GET、DELETE 和 PATCH api 调用,在我们的例子中它们没有任何负载。

【讨论】:

  • 太棒了。尽管定义内容类型会破坏没有正文的东西,这让我感到很奇怪。还是预期的返回类型会破坏事物?
  • 它在你的控制器类的顶部添加了这个:@Controller @RequestMapping(value = "/SCA_ETH_FDFr_EC", consumes={APPLICATION_JSON_VALUE},produces = {APPLICATION_JSON_VALUE}) 这显然告诉了你所有的控制器方法他们需要应用程序/json。故事的寓意是要小心你的 yaml...在 API 部分中定义消费/生产
【解决方案3】:

根据 HTTP/1.1 规范,GET 或 DELETE 请求都不应该有消息体,如果有,服务器应该忽略它。我认为这就是为什么 swagger-UI 不发送带有 GET 或 DELETE 请求的 Content-Type 标头的原因。

更多:https://www.rfc-editor.org/rfc/rfc2616#section-4.3

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-04-05
    • 2015-07-18
    • 2016-12-26
    • 1970-01-01
    • 2022-01-22
    • 2020-06-15
    • 1970-01-01
    • 2017-01-01
    相关资源
    最近更新 更多