临时文件上传不了怎么办


临时文件上传不了怎么办  

Tomcat与HTTP协议中的文件上传机制解析

作者:空无

前言

近期在另一社区看到关于Tomcat的提问,引发了我的兴趣。关于Tomcat如何处理文件上传的问题,其实有很多细节值得探讨。今天,我们就结合Tomcat机制,来聊聊这个“为什么”。本文涵盖了HTTP协议中的文件上传标准和Tomcat机制的分析,比较基础,不需要深入细节的大佬们可以直接跳到文末。

一、HTTP协议中的文件上传

HTTP是一个文本协议,那么它是如何传输文件的呢?

答案是直接传输。HTTP协议在传输层都是传输字节数据,无论是文本还是文件,都无需进行额外的编解码。

在HTTP协议中,有一种基于表单的文件上传方式(Form-based File Upload)。这种方式通过在form中定义ENCTYPE属性,值为multipart/form-data,并增加一个type为file的标签来实现。

这种multipart/form-data类型的表单和默认的x-www-form-urlencoded有所不同。虽然都可以上传多个字段,但前者可以上传文件,后者只能传输文本。

现在来看看这个表单文件上传方式的协议。在一个multipart/form-data类型的请求报文中,HTTP header部分没有变化,只是Content-Type中增加了一段boundary标签,而payload部分却完全不同。

boundary在multipart/form-data中起到分隔表单多个字段的作用。在payload部分中,首尾两行各有一个boundary,每个字段(part/item)之间也会有一个boundary。

Server端在读取时,只需要先从Content-Type中拿到boundary,然后通过这个boundary去拆分payload部分就可以获取所有的字段。

每个字段的报文中,有一个Content-Disposition字段,作为这个字段的Header部分。其中记录了当前字段名(name),如果是文件的话还会有一个filename属性,同时下一行会附带一个Content-Type来标识文件的类型。

虽然x-www-form-urlencoded和multipart两种类型的表单都可以完成字段的传输,但multipart不仅可以传输文本字段,还可以传输文件。而且这种multipart传输文件的方式也是“标准”的,各种Server都可以支持,直接读取文件。

除了这种常用的multipart方式,还有一种binary payload的方式上传文件,不过这种方式并不常用。

二、Tomcat处理机制分析

Tomcat在处理文本形式的报文时,会先读取前面的Header部分,解析Content-Length来划分报文边界,剩下的Payload部分并不会一次性读取,而是包装成一个InputStream,在内部调用Socket read进行读取RCV_BUF的数据(完整报文大小大于readBufSize时)。

对于HttpServletRequest的调用getParameter/getInputStream等涉及Payload部分读取操作时,就会进行InputStream内部的Socket RCV_BUF的读取,读取Payload的数据。

这种不一次性读取所有数据暂存至内存中的方式,而包装一个InputStream内部读取RCV_BUF的方式,特点是不存储数据,只是做一个包装,应用层对ServletRequestinputStream的read操作会转发到对Socket RCV_BUF的read。

然而对于multipart类型的请求,Tomcat处理机制上比较特殊。由于multipart是为了传输文件而设计的,所以在处理这种类型请求时,Tomcat增加了一个暂存文件的概念。在解析报文时,将multipart中的数据写入到了磁盘中。如下图所示,Tomcat对每一个字段都包装为一个DiskFileItem。

这种存储至磁盘的方式虽然方便处理大文件上传的情况,但同时也带来了一定的性能损耗和延迟问题。另外由于解析 multipart 请求的过程涉及文件系统的读写操作和网络数据传输的不确定性因素较多,所以在处理大量并发上传请求时可能会出现性能瓶颈和资源竞争问题。因此在实际应用中需要根据具体情况进行优化和调整配置以保证系统的稳定性和性能表现。

  临时文件上传不了怎么办