使用 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.InputStreamjava.io.File 参数,对应于框架用于支持文件上传的临时文件。

该方法在SwaggerOperationControllerapply方法中通过反射调用。执行此调用时,由于参数不同 - 您的方法签名定义了一个 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 ...;
}

请注意参数类型的变化。