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

Java 文件上传流从哪里获取内容?,java,http,tomcat,file-upload,tcp,Java,Http,Tomcat,File Upload,Tcp,我有一个关于文件上传的问题,这更多的是关于它是如何工作的,而不是一个代码问题。我在网上查了一下,但找不到正确的答案 我有一个在tomcat上运行的web应用程序,它(通过servlet)处理文件上传。假设我现在想上传大文件(>1GB)。我的理解是,一旦整个文件被实际传输,HTTP请求的多部分内容就可以在我的servlet中使用 我的问题是请求的内容实际存储在哪里?调用HttpServletRequest.getParts()时,Part对象上有一个InputStream。但是,流从哪里读取?To

我有一个关于文件上传的问题,这更多的是关于它是如何工作的,而不是一个代码问题。我在网上查了一下,但找不到正确的答案

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

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

我想这可能不够清楚,所以我会根据你的评论来更新这篇文章


感谢在请求过程中,
InputStream
通常会从多部分框架创建的临时文件中读取。临时文件通常存储在应用程序服务器的临时区域中——由servlet上下文属性
javax.servlet.context.tempdir
指定。在Tomcat中,这是
$CATALINA_HOME/work
下面的某个地方。请求完成后,该文件将被删除

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


如果使用Spring的
CommonsMultipartResolver
,则可以通过
maxInMemorySize
属性设置内存中允许的最大上载大小。如果上传的文件比这个大,那么它将作为临时文件存储在磁盘上。

我认为我们应该退一步,考虑一下web基础设施。首先,HTTP传输文本数据,所以二进制信息被编码,这样数据就不会被弄乱。这最终导致了大量数据,并产生了多部分表单,它将数据分解为编码文本的一部分,并使用特殊的标记,允许服务器将所有内容组装在一起。但要使用这些数据,我们必须首先对其进行解码,要做到这一点,我必须使用表单的多个部分

[休息一下,让我们可以呼吸]

继续,因此浏览器需要发送大量数据(如您在示例中提到的1GB),此数据用base64编码,然后用其标记将其分为多个部分(多部分形式),然后浏览器开始将这些部分发送到服务器,但服务器仅在完成接收和处理HTTP请求后返回HTTP响应(或者如果发生超时,则会导致浏览器屏幕上出现错误)

这里可以假设Tomcat可以(我没有检查内部)开始解码已经到达的(从临时文件或内存)将inputstream传递给用户的多部分的每个部分,因为inputstrem读取是一个阻塞操作,服务器将等待下一段数据传递给Tomcat,然后再将其传递给处理数据的程序

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


希望有帮助:)

Tomcat将
部分存储在“X:\some\path\Tomcat 7.0\temp”(/some/path/apache-Tomcat-7.0.X/temp)目录中

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

当所有部分的传输完成时,将调用servlet/jsp


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

如果您对多部分解析阶段感兴趣,可以看看ApacheCommonsFileUpload(特别是
ServletFileUpload.parseRequest()
),tomcat基于该阶段的一个变体

更新

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


Tomcat遵循Servlet 3.0规范,该规范允许您指定多部分“部分”在存储(临时)到磁盘上之前的大小、写入临时文件的位置、文件的最大大小以及整个请求的最大大小。您可以找到关于配置多部分上传的各种好信息(在Tomcat或任何其他兼容spec-3.0的服务器中)和

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

因此,如果您想要接收1GiB文件,但没有可用的内存(我不建议允许客户端在每次上传时用1GiB上传的数据填满您的堆…如果您只是同时开始几次1GiB上传,并且您是toast,那么简单的DoS),那么Tomcat(或您正在使用的任何容器)将读取该文件(同样,完整地)放到磁盘上,当servlet得到控制时,您可以从该文件中读取字节

请注意,容器必须在您的任何代码真正运行之前处理整个多部分请求。这是为了防止您通过部分读取请求的
InputStream
或诸如此类的内容来破坏任何内容。处理多部分请求非常重要,而且很容易破坏

如果您希望能够流式处理大型文件(例如,可以串行处理的大型XML文件),那么您需要自己处理多部分解析