使用 Vertx.io 框架编写用于多部分文件上传的 post API

问题描述 投票:0回答:2

我正在使用 vertx.io 编写分段文件上传的代码。

在Spring boot中我的代码如下。我想在 vertex.io 中写类似的内容

@RequestMapping(value = "/upload", headers=("content-type=multipart/*") ,method = RequestMethod.POST)
public ImportExportResponse upload(@RequestParam("file") MultipartFile inputFile){
    log.info(" upload service method starts  ");
    ImportExportResponse response = new ImportExportResponse();
    FileOutputStream fileOutputStream=null;
    try{
        File outputFile = new File(FILE_LOCATION+inputFile.getOriginalFilename());
        fileOutputStream = new FileOutputStream(outputFile);
        fileOutputStream.write(inputFile.getBytes());   
        fileOutputStream.close();

        response.setStatus(ImportExportConstants.ResponseStatus.SUCCESS.name());
        response.setErrorMessage(EMPTY);

    }catch (Exception e) {
        log.error("Exception while upload the file . "+e.getMessage());
        response.setStatus(ImportExportConstants.ResponseStatus.ERROR.name());
        response.setErrorMessage(errorMap.get(SYSTEM_ERROR_CODE));          
    }
    log.info(" upload service method ends. file is copied to a temp folder ");
    return response;
}
java multipart vert.x
2个回答
13
投票

这里是相同的,但是在 vert.x 中:

Router router = Router.router(vertx);

// Enable multipart form data parsing
router.post("/upload").handler(BodyHandler.create()
  .setUploadsDirectory(FILE_LOCATION));

// handle the form
router.post("/upload").handler(ctx -> {
  // in your example you only handle 1 file upload, here you can handle
  // any number of uploads
  for (FileUpload f : ctx.fileUploads()) {
    // do whatever you need to do with the file (it is already saved
    // on the directory you wanted...
    System.out.println("Filename: " + f.fileName());
    System.out.println("Size: " + f.size());
  }

  ctx.response().end();
});

有关更多示例,您可以随时查看 vertx-examples 存储库。


0
投票

对于 99.9% 的用例,Paulo Lopes 的答案是绝对正确的。

它的主要问题是上传的文件存储在文件系统上的临时空间中 - 您必须确保有足够的空间可用于用户将上传的所有文件;您必须确保对最大上传大小设置适当的限制,以便攻击者无法对您进行 DoS;您必须处理该文件并在完成后将其删除。

如果所有这些都让您担心并且您愿意投入额外的工作,这里介绍了如何获取上传的 Vert.x

ReadStream
- 然后您可以从中读取数据并将数据推送到有意义的地方,而不会产生任何麻烦与使用
RoutingContext.fileUploads()
相关的存储和IO:

重要提示先

如果您不希望

BodyHandler
使用上传内容并将其保存到本地文件 - 不要让它处理上传。主要有以下三种方法:

  1. 不要在要处理上传的路由(或任何父路由)上设置正文处理程序。
  2. 使用
    BodyHandler.create(false)
    创建不支持文件上传的正文处理程序。
  3. 在要处理上传的路由之后订购的路由中设置正文处理程序。这是最有问题的,因为如果在请求已经结束流式传输之后调用主体处理程序,则主体处理程序将中断请求处理,并且甚至没有错误(从 Vert.x 4.4.4 开始 - 下一个版本有这个)已修复,并且会发出错误)。要使用此方法,您必须通过暂停请求读取来处理请求,然后您自己处理上传和恢复请求读取 - 或者您需要让正文处理程序根据需要自动恢复请求。

这里我将演示选项3。

Router router = Router.router(vertx);

// Pause the request reading so we can register for handling the body later
router.route("/*").handler(ctx -> { ctx.request().pause(); ctx.next(); });

// handle the upload
router.post("/upload").handler(ctx -> {
  ctx.request().setExpectMultipart(true) // this sets up the upload handlers
    .uploadHandler(upload -> { // register our upload handler
      // this handler will be called once for each file found in the request
      var filename = upload.filename();
      var contentType = upload.contentType();
      consumeUpload(upload.pipe()); // upload is a ReadStream, so read it
    })
    .endHandler(__ -> {
      // somehow verify that all uploads were consumed successfully
      // (or figure out the correct error response)
      ctx.response().end(); // do something more meaningful here
    })
    .resume(); // after we have setup our handlers, resume the request
});

// have a body handler to handle all the other routes
// it will resume the request automatically so the body will be available
// for outher routes
router.route("/*").handler(BodyHandler.create());

// ... what ever else routes you have
© www.soinside.com 2019 - 2024. All rights reserved.