对于这块知识点,我一直都是模糊的,不是很是清楚的。在平时的工做中,遇到上传的问题,也没有深刻的去研究过,也都是直接用别人封装好的类来完成本身的工做。某一天,看了本书,说到这个知识点,一脸茫然,觉的有必要去深刻的学习一下,至少要让本身明白HTTP文件上传的过程,这个原理,以便未来出现问题,也能经过原理进行深刻的分析,而不是等问题来了,两眼一抹黑,而后漫无目的的百度。哦,若是是那样子,那该是多么的痛苦,多么的无助。html
因此查缺补漏,以避免让未来的本身感到无助、痛苦,甚至难堪,走起!!!前端
咱们在开发的时候,当要用到文件上传功能时,前端开发人员都会告诉你如下几条金科律令:java
post
;<input type="file"/>
;enctype="multipart/form-data"
。是的,咱们必须按照上面这三条铁令进行设定,不然就没法上传文件。好比咱们通常会这么写:web
<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%> <html> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <body> <form action="<%=request.getContextPath() %>/UploadServletDemo" enctype="multipart/form-data" method="post"> 上传用户:<input type="text" name="username"><br/> 上传文件1:<input type="file" name="file1"><br/> 上传文件2:<input type="file" name="file2"><br/> <input type="submit" value="提交"> </form> </body> </html>
我这里写了一个简单的Servlet:浏览器
@WebServlet("/UploadServletDemo") public class UploadServletDemo extends HttpServlet{ @Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { request.setCharacterEncoding("utf-8"); // 获取表单(POST)数据 ServletInputStream in = request.getInputStream();//此方法获得全部的提交信息,不单单只有内容 // 转换流 InputStreamReader inReaser = new InputStreamReader(in); // 缓冲流 BufferedReader reader = new BufferedReader(inReaser); String str = null; while ((str=reader.readLine()) != null){ System.out.println(str); } } }
咱们把程序跑起来,而后经过Fiddler进行抓包,能够看到咱们发送的Post请求中,请求体中有如下这样的数据:服务器
POST http://localhost:8080/javawebservlet_war/UploadServletDemo HTTP/1.1 Host: localhost:8080 Connection: keep-alive Content-Length: 446 Cache-Control: max-age=0 Origin: http://localhost:8080 Upgrade-Insecure-Requests: 1 Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryqj67FUBQUHXZj78G User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.131 Safari/537.36 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3 Referer: http://localhost:8080/javawebservlet_war/ Accept-Encoding: gzip, deflate, br Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,und;q=0.7,zh-TW;q=0.6 Cookie: JSESSIONID=6BE280EF3CBE213F73430FFDF015DE97 ------WebKitFormBoundaryqj67FUBQUHXZj78G Content-Disposition: form-data; name="username" abc ------WebKitFormBoundaryqj67FUBQUHXZj78G Content-Disposition: form-data; name="file1"; filename="文件1.txt" Content-Type: text/plain ABC文件1 ------WebKitFormBoundaryqj67FUBQUHXZj78G Content-Disposition: form-data; name="file2"; filename="文件2.txt" Content-Type: text/plain BDF文件2 ------WebKitFormBoundaryqj67FUBQUHXZj78G--
到这里,咱们就大概就知道了HTTP上传文件的原理了。HTTP把须要上传的表单的全部数据按照必定的格式存放在请求体中,对于文件也是一样的。app
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryqj67FUBQUHXZj78G
表示要上传附件,其中boundary
表示分隔符,若是表单中有多项,就要使用boundary
进行分隔,每一个表单项由------FormBoundary
开始,以------FormBoundary
结尾。例如这样:dom
------FormBoundary Content-Disposition: form-data; name="param1" value1 ------FormBoundary
这个boundary
的值是由浏览器生成的,由浏览器来保证与上传内容不重复。在每一个分隔项里,须要咱们去重点关注Content-Disposition
消息头,其中第一个参数老是固定不变的form-data
,name表示表单元素属性名,回车换行符后面的内容就是元素的值。还有Content-Type
表示咱们上传的文件的MIME类型,咱们在服务器端须要根据这个进行文件的区分。ide
HTTP就是按照这种格式,把表单中的数据封装成一个请求一股脑的发给服务器端,服务器端根据这种规则对接收到的请求进行解析,从而完成文件上传功能。post
最后一个
boundary
的结尾会多两个--
经过上面的描述,咱们能够知道完成文件上传功能,重点工做不是在于客户端,而是在于服务器端。服务器端须要根据客户端发送过来的请求,根据上面说的规则对请求报文进行解析,从而提取出上传的文件内容。能够看到,虽然上面的规则比较简单,可是用不一样的开发语言来一次性写出没有Bug的解析程序,也不是那么简单的。并且这种实现过一遍,就能够你们共享的东西就很是适合开发成组件供你们一块儿使用,因此呢,开源社区就开发了这样的一个组件,这个组件来给咱们完成了上面规则的编码,而咱们须要作的就是去学会使用这个组件,就这么简单!
下面就经过一个简单的FileUpload
Demo程序来总结一下如何使用FileUpload
组件。
下面来一段简单的使用Demo。
@WebServlet("/FileUpload") public class FileUploadDemo extends HttpServlet { @Override public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { DiskFileItemFactory fac = new DiskFileItemFactory(); ServletFileUpload upload = new ServletFileUpload(fac); upload.setFileSizeMax(10 * 1024 * 1024); upload.setSizeMax(20 * 1024 * 1024); if (upload.isMultipartContent(request)) { try { List<FileItem> list = upload.parseRequest(request); for (FileItem item : list) { if (item.isFormField()) { String fileName = item.getFieldName(); String value = item.getString("UTF-8"); System.out.println(fileName + ":" + value); } else { String name = item.getName(); String id = UUID.randomUUID().toString(); name = id + name; String realPath = getServletContext().getRealPath("/upload"); File file = new File(realPath, name); item.write(file); item.delete(); } } } catch (Exception e) { e.printStackTrace(); } } else { System.out.println("不处理!"); } } }
这篇文章对经过HTTP协议进行文件上传原理进行了比较详细的分析和总结,但愿对你们有帮助!
2019年7月31日 于内蒙古呼和浩特。