使用bodyhandler上传Java vertx 3.2文件

时间:2016-02-03 00:58:04

标签: java

java.lang.IllegalStateException:请求已在vertx3.0中读取异常。我试过很多方面。简单的formupload工作正常。但是当我使用body处理程序时,它会抛出异常。有人可以帮忙吗?

import io.vertx.core.AbstractVerticle;
import io.vertx.core.http.HttpHeaders;

import io.vertx.ext.web.Router;
import io.vertx.ext.web.handler.BodyHandler;

/*
 * @author Gogs
 */

public class TestServer extends AbstractVerticle {

  // Convenience method so you can run it in your IDE
  public static void main(String[] args) {
    Runner.runExample(TestServer.class);
  }

  @Override
  public void start() throws Exception {

    Router router = Router.router(vertx);

    // Enable multipart form data parsing
    router.route().handler(BodyHandler.create());

    router.route("/").handler(routingContext -> {
      routingContext.response().putHeader("content-type", "text/html").end(
          "<form action=\"/form\" ENCTYPE=\"multipart/form-data\" method=\"POST\" name=\"wibble\">\n" +
           "choose a file to upload:<input type=\"file\" name=\"myfile\"/><br>"+
          " <input type=\"submit\"/>"+
          "</form>"
      );
    });

    // handle the form
    router.post("/form").handler(ctx -> {

      ctx.request().setExpectMultipart(true);
      ctx.request().uploadHandler(upload -> {
          upload.exceptionHandler(cause -> {
            ctx.response().setChunked(true).end("Upload failed");
          });

          upload.endHandler(v -> {
            ctx.response().setChunked(true).end("Successfully uploaded to " + upload.filename());
          });
          // FIXME - Potential security exploit! In a real system you must check this filename
          // to make sure you're not saving to a place where you don't want!
          // Or better still, just use Vert.x-Web which controls the upload area.
          upload.streamToFileSystem(upload.filename());
        });


    });

    vertx.createHttpServer().requestHandler(router::accept).listen(8090);
  }
}

Am seeing the below exception.


Feb 02, 2016 6:48:54 PM io.vertx.ext.web.impl.RoutingContextImplBase

SEVERE: Unexpected exception in route

java.lang.IllegalStateException: Request has already been read

    at io.vertx.core.http.impl.HttpServerRequestImpl.checkEnded(HttpServerRequestImpl.java:426)
    at io.vertx.core.http.impl.HttpServerRequestImpl.setExpectMultipart(HttpServerRequestImpl.java:322)
    at io.vertx.ext.web.impl.HttpServerRequestWrapper.setExpectMultipart(HttpServerRequestWrapper.java:166)
    at com.vertx.http.upload.TestServer.lambda$1(TestServer.java:43)
    at io.vertx.ext.web.impl.RouteImpl.handleContext(RouteImpl.java:221)
    at io.vertx.ext.web.impl.RoutingContextImplBase.iterateNext(RoutingContextImplBase.java:78)
    at io.vertx.ext.web.impl.RoutingContextImpl.next(RoutingContextImpl.java:93)
    at io.vertx.ext.web.handler.impl.BodyHandlerImpl$BHandler.doEnd(BodyHandlerImpl.java:155)
    at io.vertx.ext.web.handler.impl.BodyHandlerImpl$BHandler.uploadEnded(BodyHandlerImpl.java:135)
    at io.vertx.ext.web.handler.impl.BodyHandlerImpl$BHandler.lambda$null$35(BodyHandlerImpl.java:109)
    at io.vertx.core.http.impl.HttpServerFileUploadImpl.notifyEndHandler(HttpServerFileUploadImpl.java:213)
    at io.vertx.core.http.impl.HttpServerFileUploadImpl.lambda$handleComplete$165(HttpServerFileUploadImpl.java:206)
    at io.vertx.core.file.impl.AsyncFileImpl.lambda$doClose$226(AsyncFileImpl.java:470)
    at io.vertx.core.impl.ContextImpl.lambda$wrapTask$16(ContextImpl.java:335)
    at io.netty.util.concurrent.SingleThreadEventExecutor.runAllTasks(SingleThreadEventExecutor.java:358)
    at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:357)
    at io.netty.util.concurrent.SingleThreadEventExecutor$2.run(SingleThreadEventExecutor.java:112)
    at java.lang.Thread.run(Unknown Source)

3 个答案:

答案 0 :(得分:2)

您正在阅读请求正文两次。第一次阅读是通过BodyHandler(请参阅BodyHanderImpl),第二次是您自己的处理程序(请参阅HttpServerRequestImplHttpServerFileUploadImpl)。

BodyHandler完全从请求中读取正文,并在context.body中显示。路由器的配置方式:

router.route().handler(BodyHandler.create());

在您的路由器处理的每个请求上都会完整地读取正文。

您的处理程序也在完全读取请求正文并将其内容写入文件系统。您的路由器配置为仅在对/form进行POST时执行处理程序。

回顾一下这个流程,当您向/form BodyHandler提交上传时,正在完全读取请求,将内容存储在context.body中,并将请求正文标记为已读。您的路由器匹配上传处理​​程序的uri路径,并尝试再次读取正文,但由于已经读取了异常,因此会引发异常。

一些想法......

如果您打算将上传的文件写入文件系统,那么您真的不需要在路由器中配置BodyHandler。当您需要内存中的主体以便以某种方式处理它时,您可能希望使用BodyHandler。除非您打算在路由器收到的非常单一的请求上执行处理程序,否则不应配置没有匹配条件的处理程序(即router.route().handler(...))。这种处理程序的一个很好的用例是CookieHandler。

答案 1 :(得分:0)

http://grepcode.com/file/repo1.maven.org/maven2/io.vertx/vertx-web/3.0.0/io/vertx/ext/web/impl/RouterImpl.java#RouterImpl

Gogs,我正在查看这段代码,很有可能我们可以实现自己的路由器或类似的东西,然后可以在accept方法中管理...

答案 2 :(得分:0)

我们可以创建自己的bodyhandler ...... 在我们的配置文件中提供一个被忽略的路由列表: http://grepcode.com/file/repo1.maven.org/maven2/io.vertx/vertx-web/3.0.0/io/vertx/ext/web/handler/impl/BodyHandlerImpl.java#BodyHandlerImpl