使用 swagger inflector 和 dropwizard 上传文件
File upload with swagger inflector and dropwizard
我在 Java API 中使用 swagger-inflector v.1.0.17。这是我构建 API 的来源:https://github.com/swagger-api/swagger-samples/tree/master/java/inflector-dropwizard-guice
我的文件上传API定义为:
'/orders-logo':
post:
x-swagger-router-controller: OrdersController
tags:
- orders
summary: This API is upload a logo
operationId: uploadLogo
consumes:
- multipart/form-data
produces:
- application/json
parameters:
- name: file
in: formData
description: file to upload
required: false
type: file
responses:
'200':
description: Success
schema:
$ref: '#/definitions/TokenView'
'400':
description: The request doesn't comply with the schema specified
schema:
$ref: '#/definitions/ApiError'
'401':
description: Missing or invalid Authorization header
schema:
$ref: '#/definitions/ApiError'
'500':
description: Internal server error while processing the request
schema:
$ref: '#/definitions/ApiError'
以及我在控制器中的方法:
public ResponseContext uploadLogo(RequestContext context, java.io.InputStream file) {
ResponseContext response = new ResponseContext().contentType(MediaType.APPLICATION_JSON_TYPE);
System.out.println("in here");
}
我正在尝试 CURL:
curl -i -X POST \
-H "Content-Type: multipart/form-data" \
-H 'Authorization: eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJhbm9uXzU3MjBmMGUzLTMxMzItNDQ1OC1hYjYyLTBmY2EwMDEyMjAyNCIsImlzcyI6IkNsZXZlcmdpZnQiLCJleHAiOjE2MTY1MjEwMjMsImJhc2ljIjoidHJ1ZSIsIm1lcmNoYW50IjoiaGlnaHN0cmVldHZvdWNoZXJzIn0.s-yukQincZoWevQARLNrl57SABAetBxMCOF39RSd7a7tEnds5pIgo5ekRTQgX98MlEXFyDoHe0ws7iMIo_-cOQ' \
-H 'Api-Key: 7a34526370e2c3d4f2784f874aacbc0b' \
-F "file=@download.jpeg" "http://localhost:8080/v1/orders-logo"
但我收到回复:
{"code":500,"message":"There was an error processing your request. It has been logged (ID: bad38eb089e2a71a)"}
当我查看日志时,我看到:
com.clevergift.dropwizard.InflectorExceptionMapper: There was an error processing your request. It has been logged (ID: bad38eb089e2a71a)
! java.lang.IllegalArgumentException: argument type mismatch
! at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
! at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
! at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
! at java.base/java.lang.reflect.Method.invoke(Method.java:566)
! at io.swagger.inflector.controllers.SwaggerOperationController.apply(SwaggerOperationController.java:503)
! ... 67 common frames omitted
! Causing: io.swagger.inflector.utils.ApiException: There was an error processing your request. It has been logged (ID: bad38eb089e2a71a)
! at io.swagger.inflector.controllers.SwaggerOperationController.apply(SwaggerOperationController.java:560)
! at io.swagger.inflector.controllers.SwaggerOperationController.apply(SwaggerOperationController.java:89)
! at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
! at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
! at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
! at java.base/java.lang.reflect.Method.invoke(Method.java:566)
! at org.glassfish.jersey.server.model.internal.ResourceMethodInvocationHandlerFactory.invoke(ResourceMethodInvocationHandlerFactory.java:81)
! at org.glassfish.jersey.server.model.internal.AbstractJavaResourceMethodDispatcher.run(AbstractJavaResourceMethodDispatcher.java:144)
! at org.glassfish.jersey.server.model.internal.AbstractJavaResourceMethodDispatcher.invoke(AbstractJavaResourceMethodDispatcher.java:161)
! at org.glassfish.jersey.server.model.internal.JavaResourceMethodDispatcherProvider$ResponseOutInvoker.doDispatch(JavaResourceMethodDispatcherProvider.java:160)
! at org.glassfish.jersey.server.model.internal.AbstractJavaResourceMethodDispatcher.dispatch(AbstractJavaResourceMethodDispatcher.java:99)
! at org.glassfish.jersey.server.model.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:389)
! at org.glassfish.jersey.server.model.ResourceMethodInvoker.apply(ResourceMethodInvoker.java:347)
! at org.glassfish.jersey.server.model.ResourceMethodInvoker.apply(ResourceMethodInvoker.java:102)
! at org.glassfish.jersey.server.ServerRuntime.run(ServerRuntime.java:326)
! at org.glassfish.jersey.internal.Errors.call(Errors.java:271)
! at org.glassfish.jersey.internal.Errors.call(Errors.java:267)
! at org.glassfish.jersey.internal.Errors.process(Errors.java:315)
! at org.glassfish.jersey.internal.Errors.process(Errors.java:297)
! at org.glassfish.jersey.internal.Errors.process(Errors.java:267)
! at org.glassfish.jersey.process.internal.RequestScope.runInScope(RequestScope.java:317)
! at org.glassfish.jersey.server.ServerRuntime.process(ServerRuntime.java:305)
! at org.glassfish.jersey.server.ApplicationHandler.handle(ApplicationHandler.java:1154)
! at org.glassfish.jersey.servlet.WebComponent.serviceImpl(WebComponent.java:473)
! at org.glassfish.jersey.servlet.WebComponent.service(WebComponent.java:427)
! at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:388)
! at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:341)
! at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:228)
! at io.dropwizard.jetty.NonblockingServletHolder.handle(NonblockingServletHolder.java:49)
! at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1623)
! at io.dropwizard.servlets.ThreadNameFilter.doFilter(ThreadNameFilter.java:35)
! at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1610)
! at io.dropwizard.jersey.filter.AllowedMethodsFilter.handle(AllowedMethodsFilter.java:45)
! at io.dropwizard.jersey.filter.AllowedMethodsFilter.doFilter(AllowedMethodsFilter.java:39)
! at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1610)
! at com.clevergift.filters.ApiKeyFilter.doFilter(ApiKeyFilter.java:99)
! at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1610)
! at com.clevergift.filters.CORSFilter.doFilter(CORSFilter.java:15)
! at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1610)
! at com.google.inject.servlet.FilterChainInvocation.doFilter(FilterChainInvocation.java:89)
! at com.google.inject.servlet.ManagedFilterPipeline.dispatch(ManagedFilterPipeline.java:121)
! at com.google.inject.servlet.GuiceFilter.doFilter(GuiceFilter.java:133)
! at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1610)
! at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:540)
! at org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:255)
! at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1345)
! at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:203)
! at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:480)
! at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:201)
! at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1247)
! at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:144)
! at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:132)
! at com.codahale.metrics.jetty9.InstrumentedHandler.handle(InstrumentedHandler.java:239)
! at io.dropwizard.jetty.RoutingHandler.handle(RoutingHandler.java:52)
! at org.eclipse.jetty.server.handler.gzip.GzipHandler.handle(GzipHandler.java:703)
! at io.dropwizard.jetty.BiDiGzipHandler.handle(BiDiGzipHandler.java:67)
! at org.eclipse.jetty.server.handler.RequestLogHandler.handle(RequestLogHandler.java:56)
! at org.eclipse.jetty.server.handler.StatisticsHandler.handle(StatisticsHandler.java:174)
! at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:132)
! at org.eclipse.jetty.server.Server.handle(Server.java:505)
! at org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:370)
! at org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:267)
! at org.eclipse.jetty.io.AbstractConnection$ReadCallback.succeeded(AbstractConnection.java:305)
! at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:103)
! at org.eclipse.jetty.io.ChannelEndPoint.run(ChannelEndPoint.java:117)
! at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:698)
! at org.eclipse.jetty.util.thread.QueuedThreadPool$Runner.run(QueuedThreadPool.java:804)
! at java.base/java.lang.Thread.run(Thread.java:834)
0:0:0:0:0:0:0:1 - - [25/Jan/2021:16:12:03 +0000] "POST /v1/orders-logo HTTP/1.1" 500 110 "-" "curl/7.64.1" 5
我使用的是 swagger-inflector 1.0.17 版。知道我做错了什么吗?
也许这可以帮助你,这是由于 swagger 的 版本 以及文件上传 API 的定义方式:
Finally I found answer for this, actually previously there is no
support for file upload, now they updated swagger-ui.js file. You need
to replace your old one with new and also you have to define these
properties under Parameters for particular parameter:
"paramType": "formData",
"dataType": "file",
当操作 returns 按 ID 分配的资源且参数无效时,似乎会出现 404 Not Found 响应。
可能是参数没有定义好或者这个路径找不到
我在这里看到了另一个 post 类似问题的答案:
Whosebug post
更新:
从错误跟踪来看,转换参数时似乎是 Jackson 或 Jersey 错误。
在开发模式下,有一个 /debug.json
页面显示了 inflector 服务的实现细节。
如果您的 Swagger 描述无法解析,服务器将在启动时抛出难看的错误,debug.json
页面将给出原因说明。
你可以看到这个文档here
看起来正在调用 uploadLogo
而不是 java.io.InputStream
和 java.io.File
参数,对应于框架用于支持文件上传的临时文件。
该方法在SwaggerOperationController
的apply
方法中通过反射调用。执行此调用时,由于参数不同 - 您的方法签名定义了一个 java.io.InputStream
但框架将 java.io.File
作为参数传递 - 您将获得指示的异常:
java.lang.IllegalArgumentException: argument type mismatch
请试试这个签名:
public ResponseContext uploadLogo(RequestContext context, java.io.File file) {
ResponseContext response = new ResponseContext().contentType(MediaType.APPLICATION_JSON_TYPE);
System.out.println("in here");
// The rest of your code
return ...;
}
请注意参数类型的变化。
我在 Java API 中使用 swagger-inflector v.1.0.17。这是我构建 API 的来源:https://github.com/swagger-api/swagger-samples/tree/master/java/inflector-dropwizard-guice
我的文件上传API定义为:
'/orders-logo':
post:
x-swagger-router-controller: OrdersController
tags:
- orders
summary: This API is upload a logo
operationId: uploadLogo
consumes:
- multipart/form-data
produces:
- application/json
parameters:
- name: file
in: formData
description: file to upload
required: false
type: file
responses:
'200':
description: Success
schema:
$ref: '#/definitions/TokenView'
'400':
description: The request doesn't comply with the schema specified
schema:
$ref: '#/definitions/ApiError'
'401':
description: Missing or invalid Authorization header
schema:
$ref: '#/definitions/ApiError'
'500':
description: Internal server error while processing the request
schema:
$ref: '#/definitions/ApiError'
以及我在控制器中的方法:
public ResponseContext uploadLogo(RequestContext context, java.io.InputStream file) {
ResponseContext response = new ResponseContext().contentType(MediaType.APPLICATION_JSON_TYPE);
System.out.println("in here");
}
我正在尝试 CURL:
curl -i -X POST \
-H "Content-Type: multipart/form-data" \
-H 'Authorization: eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJhbm9uXzU3MjBmMGUzLTMxMzItNDQ1OC1hYjYyLTBmY2EwMDEyMjAyNCIsImlzcyI6IkNsZXZlcmdpZnQiLCJleHAiOjE2MTY1MjEwMjMsImJhc2ljIjoidHJ1ZSIsIm1lcmNoYW50IjoiaGlnaHN0cmVldHZvdWNoZXJzIn0.s-yukQincZoWevQARLNrl57SABAetBxMCOF39RSd7a7tEnds5pIgo5ekRTQgX98MlEXFyDoHe0ws7iMIo_-cOQ' \
-H 'Api-Key: 7a34526370e2c3d4f2784f874aacbc0b' \
-F "file=@download.jpeg" "http://localhost:8080/v1/orders-logo"
但我收到回复:
{"code":500,"message":"There was an error processing your request. It has been logged (ID: bad38eb089e2a71a)"}
当我查看日志时,我看到:
com.clevergift.dropwizard.InflectorExceptionMapper: There was an error processing your request. It has been logged (ID: bad38eb089e2a71a)
! java.lang.IllegalArgumentException: argument type mismatch
! at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
! at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
! at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
! at java.base/java.lang.reflect.Method.invoke(Method.java:566)
! at io.swagger.inflector.controllers.SwaggerOperationController.apply(SwaggerOperationController.java:503)
! ... 67 common frames omitted
! Causing: io.swagger.inflector.utils.ApiException: There was an error processing your request. It has been logged (ID: bad38eb089e2a71a)
! at io.swagger.inflector.controllers.SwaggerOperationController.apply(SwaggerOperationController.java:560)
! at io.swagger.inflector.controllers.SwaggerOperationController.apply(SwaggerOperationController.java:89)
! at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
! at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
! at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
! at java.base/java.lang.reflect.Method.invoke(Method.java:566)
! at org.glassfish.jersey.server.model.internal.ResourceMethodInvocationHandlerFactory.invoke(ResourceMethodInvocationHandlerFactory.java:81)
! at org.glassfish.jersey.server.model.internal.AbstractJavaResourceMethodDispatcher.run(AbstractJavaResourceMethodDispatcher.java:144)
! at org.glassfish.jersey.server.model.internal.AbstractJavaResourceMethodDispatcher.invoke(AbstractJavaResourceMethodDispatcher.java:161)
! at org.glassfish.jersey.server.model.internal.JavaResourceMethodDispatcherProvider$ResponseOutInvoker.doDispatch(JavaResourceMethodDispatcherProvider.java:160)
! at org.glassfish.jersey.server.model.internal.AbstractJavaResourceMethodDispatcher.dispatch(AbstractJavaResourceMethodDispatcher.java:99)
! at org.glassfish.jersey.server.model.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:389)
! at org.glassfish.jersey.server.model.ResourceMethodInvoker.apply(ResourceMethodInvoker.java:347)
! at org.glassfish.jersey.server.model.ResourceMethodInvoker.apply(ResourceMethodInvoker.java:102)
! at org.glassfish.jersey.server.ServerRuntime.run(ServerRuntime.java:326)
! at org.glassfish.jersey.internal.Errors.call(Errors.java:271)
! at org.glassfish.jersey.internal.Errors.call(Errors.java:267)
! at org.glassfish.jersey.internal.Errors.process(Errors.java:315)
! at org.glassfish.jersey.internal.Errors.process(Errors.java:297)
! at org.glassfish.jersey.internal.Errors.process(Errors.java:267)
! at org.glassfish.jersey.process.internal.RequestScope.runInScope(RequestScope.java:317)
! at org.glassfish.jersey.server.ServerRuntime.process(ServerRuntime.java:305)
! at org.glassfish.jersey.server.ApplicationHandler.handle(ApplicationHandler.java:1154)
! at org.glassfish.jersey.servlet.WebComponent.serviceImpl(WebComponent.java:473)
! at org.glassfish.jersey.servlet.WebComponent.service(WebComponent.java:427)
! at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:388)
! at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:341)
! at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:228)
! at io.dropwizard.jetty.NonblockingServletHolder.handle(NonblockingServletHolder.java:49)
! at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1623)
! at io.dropwizard.servlets.ThreadNameFilter.doFilter(ThreadNameFilter.java:35)
! at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1610)
! at io.dropwizard.jersey.filter.AllowedMethodsFilter.handle(AllowedMethodsFilter.java:45)
! at io.dropwizard.jersey.filter.AllowedMethodsFilter.doFilter(AllowedMethodsFilter.java:39)
! at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1610)
! at com.clevergift.filters.ApiKeyFilter.doFilter(ApiKeyFilter.java:99)
! at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1610)
! at com.clevergift.filters.CORSFilter.doFilter(CORSFilter.java:15)
! at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1610)
! at com.google.inject.servlet.FilterChainInvocation.doFilter(FilterChainInvocation.java:89)
! at com.google.inject.servlet.ManagedFilterPipeline.dispatch(ManagedFilterPipeline.java:121)
! at com.google.inject.servlet.GuiceFilter.doFilter(GuiceFilter.java:133)
! at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1610)
! at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:540)
! at org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:255)
! at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1345)
! at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:203)
! at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:480)
! at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:201)
! at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1247)
! at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:144)
! at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:132)
! at com.codahale.metrics.jetty9.InstrumentedHandler.handle(InstrumentedHandler.java:239)
! at io.dropwizard.jetty.RoutingHandler.handle(RoutingHandler.java:52)
! at org.eclipse.jetty.server.handler.gzip.GzipHandler.handle(GzipHandler.java:703)
! at io.dropwizard.jetty.BiDiGzipHandler.handle(BiDiGzipHandler.java:67)
! at org.eclipse.jetty.server.handler.RequestLogHandler.handle(RequestLogHandler.java:56)
! at org.eclipse.jetty.server.handler.StatisticsHandler.handle(StatisticsHandler.java:174)
! at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:132)
! at org.eclipse.jetty.server.Server.handle(Server.java:505)
! at org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:370)
! at org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:267)
! at org.eclipse.jetty.io.AbstractConnection$ReadCallback.succeeded(AbstractConnection.java:305)
! at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:103)
! at org.eclipse.jetty.io.ChannelEndPoint.run(ChannelEndPoint.java:117)
! at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:698)
! at org.eclipse.jetty.util.thread.QueuedThreadPool$Runner.run(QueuedThreadPool.java:804)
! at java.base/java.lang.Thread.run(Thread.java:834)
0:0:0:0:0:0:0:1 - - [25/Jan/2021:16:12:03 +0000] "POST /v1/orders-logo HTTP/1.1" 500 110 "-" "curl/7.64.1" 5
我使用的是 swagger-inflector 1.0.17 版。知道我做错了什么吗?
也许这可以帮助你,这是由于 swagger 的 版本 以及文件上传 API 的定义方式:
Finally I found answer for this, actually previously there is no support for file upload, now they updated swagger-ui.js file. You need to replace your old one with new and also you have to define these properties under Parameters for particular parameter:
"paramType": "formData",
"dataType": "file",
当操作 returns 按 ID 分配的资源且参数无效时,似乎会出现 404 Not Found 响应。
可能是参数没有定义好或者这个路径找不到
我在这里看到了另一个 post 类似问题的答案: Whosebug post
更新:
从错误跟踪来看,转换参数时似乎是 Jackson 或 Jersey 错误。
在开发模式下,有一个 /debug.json
页面显示了 inflector 服务的实现细节。
如果您的 Swagger 描述无法解析,服务器将在启动时抛出难看的错误,debug.json
页面将给出原因说明。
你可以看到这个文档here
看起来正在调用 uploadLogo
而不是 java.io.InputStream
和 java.io.File
参数,对应于框架用于支持文件上传的临时文件。
该方法在SwaggerOperationController
的apply
方法中通过反射调用。执行此调用时,由于参数不同 - 您的方法签名定义了一个 java.io.InputStream
但框架将 java.io.File
作为参数传递 - 您将获得指示的异常:
java.lang.IllegalArgumentException: argument type mismatch
请试试这个签名:
public ResponseContext uploadLogo(RequestContext context, java.io.File file) {
ResponseContext response = new ResponseContext().contentType(MediaType.APPLICATION_JSON_TYPE);
System.out.println("in here");
// The rest of your code
return ...;
}
请注意参数类型的变化。