文件上传流从哪里获取内容?

时间:2013-11-27 12:34:32

标签: java http tomcat file-upload tcp

我有一个关于文件上传的问题,这与它的工作原理有关,而不是代码问题。我在网上看了一下,但找不到合适的答案。

我有一个在tomcat上运行的Web应用程序,它处理文件上传(通过servlet)。假设我现在要上传大文件(> 1 Gb)。我的理解是,一旦实际传输了整个文件,HTTP请求的多部分内容就可以在我的servlet中使用。

我的问题是请求的内容实际存储在哪里?当一个人调用HttpServletRequest.getParts() InputStream对象上有Part时。但是,从哪里读取流? Tomcat将它存储在某个地方吗?

我想这可能不够清楚,所以如果有的话,我会根据您的评论更新帖子。

由于

5 个答案:

答案 0 :(得分:7)

Tomcat将Part存储在“X:\ some \ path \ Tomcat 7.0 \ temp”(/some/path/apache-tomcat-7.0.x/temp)目录中。

解析多部分请求时,如果单个部分的大小超过阈值,则为该部分创建临时文件。

在完成所有部件的传输后,将调用您的servlet / jsp。

当请求被销毁时,所有临时文件也会被删除。

如果您对多部分解析阶段感兴趣,请查看apache commons-fileupload(具体为ServletFileUpload.parseRequest()),tomcat基于该部分的变体

<强>更新

您可以将其配置为java arg,即在windows中:

enter image description here

答案 1 :(得分:3)

InputStream通常会从请求期间由multipart框架创建的临时文件中读取。临时文件通常存储在应用程序服务器的临时区域中 - 由servlet上下文属性javax.servlet.context.tempdir指定。在Tomcat中,这位于$CATALINA_HOME/work之下。请求完成后,该文件将被删除。

对于小文件大小,多部分框架可能会将整个上传保留在内存中 - 在这种情况下,InputStream将直接从内存中读取。

如果您使用的是Spring CommonsMultipartResolver,则可以通过maxInMemorySize属性设置内存中允许的最大上传大小。如果上传大于此值,则它将作为临时文件存储在磁盘上。

答案 2 :(得分:2)

我认为我们应该退一步,对网络基础设施进行思考。首先,HTTP传输文本数据,因此在base 64中编码的二进制信息使得数据不会被搞砸。这最终会导致大量的数据,这就产生了多部分形式,它将数据分成编码文本的一部分,并带有特殊标记,允许服务器将所有内容组合在一起。但是要使用这些数据,我们必须首先解码它,为此,我必须使用表单的多个部分。

[休息让我们可以呼吸]

继续,所以浏览器需要发送大量数据(如你在例子中提到的1GB),这个数据用base64编码,然后用它的标记分成几部分(多部分形式),然后浏览器开始发送服务器的各个部分,但服务器只有在完成接收处理HTTP REQUEST后才会返回HTTP RESPONSE(或者如果发生超时,则会在浏览器屏幕上出现错误)。< / p>

假设在这里是什么?Tomcat可以(我没有检查内部)开始解码已经存在的多部分的每个部分(来自临时文件或来自内存)传递对用户的输入流,因为inputstrem读取是阻塞操作,服务器将等待下一条数据传递给Tomcat,然后Tomcat将其传递给正在处理数据的程序。

一旦所有数据都到达服务器,程序就会准备Tomcat返回浏览器的响应,完成HTTP请求 - 响应周期关闭连接(因为HTTP是无连接协议)。

希望有所帮助:)

答案 3 :(得分:2)

Tomcat遵循Servlet 3.0规范,该规范允许您指定诸如多部分“部分”在磁盘上存储(临时)之前可以有多大的内容,临时文件将写入的位置,最大大小为一个文件,以及整个请求的最大大小。您可以找到有关配置分段上传的各种有用信息(在Tomcat或任何其他符合规范3.0的服务器中)herehere

Tomcat的实现细节并不十分相关:它遵守规范。如果要上载的文件小于设置的阈值,那么您应该能够从内存中读取文件的字节(即不涉及磁盘)。如果文件较大,则首先(完整地)将其写入磁盘,然后您可以从容器中获取字节。

因此,如果你想收到一个1GiB文件并且没有那种可用的内存(我不建议允许客户端为每次上传提供1GiB的上传数据填充你的容易...如果你愿意的话你只需要开始几个同时上传的1GiB并且你是吐司),然后Tomcat(或你正在使用的任何容器)将把文件(再次,完整地)读到磁盘上,当你的servlet获得控制权时,你可以读取字节从那个文件回来。

请注意,在您的任何代码真正运行之前,容器必须处理整个多部分请求。这是为了防止你通过部分阅读请求的InputStream或类似的东西来破坏任何东西。处理多部分请求并非易事,而且很容易破解。

如果您希望能够流式处理大型文件以进行处理(例如,可以串行处理的大型XML文件),那么您将需要自己处理多部分解析。这样,您不需要大量的堆来缓冲文件,并且在开始处理之前不需要将文件存储在磁盘上。 (如果这是您的用例,我建议使用HTTP PUT或HTTP POST而不使用多部分请求。)

(值得一提的是,在任何多部分处理规范中都没有提到base64编码。有些人在这里提到了base64,但我从未见过标准的web客户端使用base64来使用multipart / form-上传文件 - 数据.HTTP处理二进制上传就好了,谢谢。)

答案 4 :(得分:0)

这是

  1. 用户的浏览器撰写http多部分请求
  2. 用户操作系统的Tcp / ip堆栈将它们分成数据包
  3. 互联网上的路由器将这些数据包传递到您的服务器
  4. 服务器操作系统的Tcp / ip堆栈返回有效负载并传递它们 to tcp port listener
  5. Tomcat http连接器解码来自tcp数据的http post请求 (源代码是 https://github.com/apache/tomcat/tree/trunk/java/org/apache/coyote
  6. Tomcat http连接器包装一个Http Request并最终转发到 你的servlet(https://github.com/apache/tomcat/blob/trunk/java/org/apache/catalina/connector/Request.java
  7. 在您的代码读取Http Request的内容之前和之后,tomcat将在内部缓冲http请求体
  8. 在调用request.getParts()(https://github.com/apache/tomcat/blob/trunk/java/org/apache/catalina/connector/Request.java#L2561)之前,Tomcat不会解析多个部件主体,因此在调用之前没有部件的临时文件。
  9. Tomcat将上传到位置的文件存储在servlet代码中由@MultipartConfig注释指向,除非您的代码未提供并且设置了allowCasualMultipartParsing(http://tomcat.apache.org/tomcat-7.0-doc/config/context.html#Common_Attributes
  10. 默认情况下,考虑allowCasualMultipartParsing为false,您不必担心tomcat存储文件的位置,尽管很容易挖掘。
  11. 我提到1~5,因为了解Servlet 3.x request.getParts()功能之前需要的request.getInputStream()返回流非常重要。通常,tomcat很快就会向web应用程序发送请求,没有必要等待客户端完成上传,因此tomcat不需要缓冲大量数据。在JSR-000315获得批准之前,我已离开java服务器端多年:-)