【问题标题】:Setting file size restrictions when uploading files with Jersey使用 Jersey 上传文件时设置文件大小限制
【发布时间】:2011-12-26 20:18:11
【问题描述】:

我目前正在实现使用 jersey rest 上传文件的功能。我想设置允许的最大文件大小,这对我来说似乎是一个很常见的要求。

我的第一种方法是使用 Jerseys FormDataContentDisposition,它应该包含我可能需要的有关文件的所有信息。但是除了文件名之外的所有信息似乎都丢失了,包括文件大小。

这是我的休息方法:

@POST
@Path("uploadFile/")
@Consumes("multipart/form-data")
@Produces("text/html")
public String handleDocumentUpload(
    @FormDataParam("file") InputStream uploadedInputStream,
    @FormDataParam("file") FormDataContentDisposition fileDetail)
{
    if(fileDetail.getSize() > MAX_FILE_SIZE)
    {
        throw new IllegalArgumentException(
                "File is to big! Max size is " + MAX_FILE_SIZE);
    }
    // ...more file handling logic
}

这不起作用,因为返回的大小始终为“-1”!

我使用一个极其简单的html表单进行文件上传:

<html>
  <head>
    <title>File upload</title>
  </head>
  <body>
 <p>Choose file</p>
 <form enctype="multipart/form-data" method="POST" action="uploadFile">
   <input type="file" name="file" size="50">
   <input type="submit" value="Upload">
 </form>
  </body>
</html>

现在回答我的问题;您将如何使用球衣强制执行文件大小限制?必须有一些简单的方法,而不必求助于将整个文件读入内存(ByteArray)然后获取实际大小,对吗?

【问题讨论】:

标签: java rest file-upload jersey multipartform-data


【解决方案1】:

如果你使用的是 tomcat,你可以设置 the size threshold at which the file will be written to the disk 为您的机器设置一个合理的值。

例如如果 servlet 在 web.xml 中

<servlet>
  <servlet-name>Upload Servlet</servlet-name>
  <servlet-class>YourServletName</servlet-class>

  <multipart-config>
   <!-- 10MB of files -->
   <max-file-size>10485760</max-file-size>
   <!-- 10KB of form data -->
   <max-request-size>10240</max-request-size>
   <!-- Buffer to disk over 512KB -->
   <file-size-threshold>524288</file-size-threshold>
 </multipart-config>

</servlet>

或使用注释:

@MultipartConfig(
    maxFileSize=10485760,     // 10Mb max
    fileSizeThreshold=524288, //512 Kb before buffering to disk
    maxRequestSize=10240      // 10Kb of meta data
    location=/tmp             // with permission to write, default uses tomcat tmp
)

参考HttpRequest maximum allowable size in tomcat?

【讨论】:

  • docs.oracle.com/javaee/7/tutorial/servlets011.htm 之后,我会说 max-file-size 仅适用于一个文件,而 max-request-size 适用于整个请求(因此可能是多个文件和多部分)。
  • MultipartConfig 不被 JAX-RS/Jersey 使用,因为它用于 Servlet 而不是 JAX-RS 资源。泽西岛的 MultipartConfig 没有等价物。详情请参考jersey.github.io/documentation/latest/media.html#multipart。没有快速失败的解决方案。不能依赖内容长度标头。我们必须检查文件的大小并在大于预设阈值时拒绝它。为什么这么可怕?想象一个巨大的文件被上传。 Jersey 必须先将整个文件保存在磁盘上;如果服务器的磁盘空间有限,这不仅耗时而且不安全。
【解决方案2】:

您可以通过读取标头来获取请求大小。 在您的示例中:

@POST
@Path("uploadFile/")
@Consumes("multipart/form-data")
@Produces("text/html")
public String handleDocumentUpload(
    @HeaderParam("content-length") long contentLength,
    @FormDataParam("file") InputStream uploadedInputStream,
    @FormDataParam("file") FormDataContentDisposition fileDetail) {

    if(contentLength > MAX_FILE_SIZE) {
      throw new IllegalArgumentException(
            "File is to big! Max size is " + MAX_FILE_SIZE);
    }
  // ...more file handling logic
}

【讨论】:

  • 内容长度可以捏造
【解决方案3】:

你可以有你的自定义class LimitedSizeInputStream extends InputStream 使用@Override 读取检查https://stackoverflow.com/a/30072143/5962766 中提到的特定大小限制的方法。用new LimitedSizeInputStream(fileStream, FILE_SIZE_LIMIT) 包裹你的InputStream,当达到读取限制时你会得到异常。

【讨论】:

    【解决方案4】:

    您可以使用以下代码检查请求正文的长度(以字节为单位)并由输入流提供:

    public Response uploadFile(@Context final HttpServletRequest request, @FormDataParam("uploadFile") InputStream uploadedInputStream,
          @FormDataParam("uploadFile") FormDataContentDisposition fileDetail, @FormDataParam("uploadFile") FormDataBodyPart body) {
    

    关键部分是@Context final HttpServletRequest request。然后在方法体中,你可以得到输入流的长度并做出相应的反应:

    int contentLength = request.getContentLength();
    
    if (contentLength == -1 || contentLength > MAX_REQUEST_SIZE) {
      // deal with it
    }
    

    【讨论】:

    • 在这种情况下,假设您想将文件大小限制在1gb 以上,所以your validation comes in picture once we upload whole file。所以它真的很慢而且不能接受。你考虑过这个案子吗?
    【解决方案5】:

    如果客户端没有发送文件大小,则退回到从流中读取文件。一旦达到大小限制,请停止阅读并拒绝该文件。无论如何你都应该这样做,因为你不能信任客户端(任何人都可以创建一个向你的服务发送 http 请求的应用程序,而这些请求可能没有你期望的正确数据 - 所以必须考虑到这一点)。

    此外,也可以向 Web 表单添加一些验证以快速失败,但我不是 JavaScript 专家,所以不确定是否/如何做到这一点。

    【讨论】:

    • 谢谢马丁!你当然是对的,我不应该指望客户给我正确的文件大小。我们实现了它,如果客户端声明的文件大小> MAX_SIZE,那么我们“快速失败”,否则我们读取流直到达到MAX_SIZE。我们发现没有简单的方法可以在客户端验证文件大小,因此必须这样做。再次感谢您的意见!
    • 为了防止您的 API 接收到不需要的 HTTP 调用,您可以创建一个 CORS 过滤器。
    猜你喜欢
    • 1970-01-01
    • 2015-08-16
    • 2012-12-13
    • 2016-04-14
    • 2011-01-29
    • 2017-03-09
    • 2011-01-13
    • 1970-01-01
    • 2022-10-26
    相关资源
    最近更新 更多