我有一个关于文件上传的问题,这与它的工作原理有关,而不是代码问题。我在网上看了一下,但找不到合适的答案。
我有一个在tomcat上运行的Web应用程序,它处理文件上传(通过servlet)。假设我现在要上传大文件(> 1 Gb)。我的理解是,一旦实际传输了整个文件,HTTP请求的多部分内容就可以在我的servlet中使用。
我的问题是请求的内容实际存储在哪里?当一个人调用HttpServletRequest.getParts()
InputStream
对象上有Part
时。但是,从哪里读取流? Tomcat将它存储在某个地方吗?
我想这可能不够清楚,所以如果有的话,我会根据您的评论更新帖子。
由于
答案 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中:
答案 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的服务器中)here和here。
Tomcat的实现细节并不十分相关:它遵守规范。如果要上载的文件小于设置的阈值,那么您应该能够从内存中读取文件的字节(即不涉及磁盘)。如果文件较大,则首先(完整地)将其写入磁盘,然后您可以从容器中获取字节。
因此,如果你想收到一个1GiB文件并且没有那种可用的内存(我不建议允许客户端为每次上传提供1GiB的上传数据填充你的容易...如果你愿意的话你只需要开始几个同时上传的1GiB并且你是吐司),然后Tomcat(或你正在使用的任何容器)将把文件(再次,完整地)读到磁盘上,当你的servlet获得控制权时,你可以读取字节从那个文件回来。
请注意,在您的任何代码真正运行之前,容器必须处理整个多部分请求。这是为了防止你通过部分阅读请求的InputStream
或类似的东西来破坏任何东西。处理多部分请求并非易事,而且很容易破解。
如果您希望能够流式处理大型文件以进行处理(例如,可以串行处理的大型XML文件),那么您将需要自己处理多部分解析。这样,您不需要大量的堆来缓冲文件,并且在开始处理之前不需要将文件存储在磁盘上。 (如果这是您的用例,我建议使用HTTP PUT或HTTP POST而不使用多部分请求。)
(值得一提的是,在任何多部分处理规范中都没有提到base64编码。有些人在这里提到了base64,但我从未见过标准的web客户端使用base64来使用multipart / form-上传文件 - 数据.HTTP处理二进制上传就好了,谢谢。)
答案 4 :(得分:0)
这是
我提到1~5,因为了解Servlet 3.x request.getParts()功能之前需要的request.getInputStream()返回流非常重要。通常,tomcat很快就会向web应用程序发送请求,没有必要等待客户端完成上传,因此tomcat不需要缓冲大量数据。在JSR-000315获得批准之前,我已离开java服务器端多年:-)