在上一篇文章中我们主要介绍了 tomcat nio 中的长连接,包括长连接开启和关闭的条件,每个长连接可以复用的请求数目等等,在这里我们介绍 tomcat 对文件上传的支持。
对于 http 协议来说,文件上传一般会为 POST 请求的 muti-part 类型,即请求中会包含 content-type 值为 multipart/form-data 的请求头。对于这种请求主要包含下面两个项:
文件上传的trigger
根据以前文章,消费 servlet 的 inputstream 就会触发解析请求体,对于 multipart/form-data 类型的请求就会完成对文件上传的支持。对于 servlet API 来说,调用 HttpServletRequest 对象实例的 getParameter()
/getParameterMap()/getParameterNames()/getParameterValues() 等方法都会触发解析请求体,所以对这些 API 的调用就间接完成了文件上传的支持。
另外如果我们调用 HttpServletRequest 对象实例的 getParts() 或者是 getPart() 方法, 就会直接获取到 multipart/form-data 类型的请求体中的各个 part,可以得到每个 part(文件) 的 inputstream ,name,size 等信息。并且如果获取了文件的 inputstream 之后,就可以根据逻辑完成我们对文件的操作。所以这两个 API 会直接完成文件上传操作。
文件上传的本质
对于 tomcat 上传文件来说,其本质是把文件上传到 tomcat 工作目录中,通过getPart() 等 API 得到的 inputstream 已经是上传在工作目录中磁盘中文件的输入流了。关于文件上传路径的核心代码在以前文章介绍的 tomcat request 对象的 parseParts() 方法里,核心逻辑如下:
// parseParts() method in org.apache.catalina.connector.Request
String locationStr = mce.getLocation();
if (locationStr == null || locationStr.length() == 0) {
location = ((File) context.getServletContext().getAttribute(ServletContext.TEMPDIR));
} else {
location = new File(locationStr);
if (!location.isAbsolute()) {
location = new File((File) context.getServletContext().getAttribute(ServletContext.TEMPDIR), locationStr).getAbsoluteFile();
}
}
总结一下 tomcat 对于文件上传的支持: