HTTP文件上传原理
前言
对于这块知识点,我一直都是模糊的,不是非常清楚的。在平时的工作中,遇到上传的问题,也没有深入的去研究过,也都是直接用别人封装好的类来完成自己的工作。某一天,看了本书,说到这个知识点,一脸茫然,觉的有必要去深入的学习一下,至少要让自己明白HTTP文件上传的过程,这个原理,以便将来出现问题,也能通过原理进行深入的分析,而不是等问题来了,两眼一抹黑,然后漫无目的的百度。哦,如果是那样子,那该是多么的痛苦,多么的无助。
所以查缺补漏,以免让将来的自己感到无助、痛苦,甚至难堪,走起!!!
HTTP上传原理
我们在开发的时候,当要用到文件上传功能时,前端开发人员都会告诉你以下几条金科律令:
- 提交方式必须为
post; - 表单中有文件上传的表单项必须为
<input type="file"/>; - 必须指定表单类型
enctype="multipart/form-data"。
是的,我们必须按照上面这三条铁令进行设定,否则就无法上传文件。比如我们一般会这么写:
<%@ 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把需要上传的表单的所有数据按照一定的格式存放在请求体中,对于文件也是同样的。
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryqj67FUBQUHXZj78G表示要上传附件,其中boundary表示分隔符,如果表单中有多项,就要使用boundary进行分隔,每个表单项由------FormBoundary开始,以------FormBoundary结尾。例如这样:
------FormBoundary
Content-Disposition: form-data; name="param1"
value1
------FormBoundary
这个boundary的值是由浏览器生成的,由浏览器来保证与上传内容不重复。在每个分隔项里,需要我们去重点关注Content-Disposition消息头,其中第一个参数总是固定不变的form-data,name表示表单元素属性名,回车换行符后面的内容就是元素的值。还有Content-Type表示我们上传的文件的MIME类型,我们在服务器端需要根据这个进行文件的区分。
HTTP就是按照这种格式,把表单中的数据封装成一个请求一股脑的发给服务器端,服务器端根据这种规则对接收到的请求进行解析,从而完成文件上传功能。
最后一个
boundary的结尾会多两个--
FileUpload组件
通过上面的描述,我们可以知道完成文件上传功能,重点工作不是在于客户端,而是在于服务器端。服务器端需要根据客户端发送过来的请求,根据上面说的规则对请求报文进行解析,从而提取出上传的文件内容。可以看到,虽然上面的规则比较简单,但是用不同的开发语言来一次性写出没有Bug的解析程序,也不是那么简单的。而且这种实现过一遍,就可以大家共享的东西就非常适合开发成组件供大家一起使用,所以呢,开源社区就开发了这样的一个组件,这个组件来给我们完成了上面规则的编码,而我们需要做的就是去学会使用这个组件,就这么简单!
下面就通过一个简单的FileUploadDemo程序来总结一下如何使用FileUpload组件。
FileUpload Demo
下面来一段简单的使用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日 于内蒙古呼和浩特。
HTTP文件上传原理的更多相关文章
- Spring Boot 文件上传原理
首先我们要知道什么是Spring Boot,这里简单说一下,Spring Boot可以看作是一个框架中的框架--->集成了各种框架,像security.jpa.data.cloud等等,它无须关 ...
- php文件上传原理详解(含源码)
1.文件上传原理 将客户端的文件上传到服务器,再将服务器的临时文件上传到指定目录 2.客户端配置 提交表单 表单的发送方式为post 添加enctype="multipart/form-da ...
- 补习系列(11)-springboot 文件上传原理
目录 一.文件上传原理 二.springboot 文件机制 临时文件 定制配置 三.示例代码 A. 单文件上传 B. 多文件上传 C. 文件上传异常 D. Bean 配置 四.文件下载 小结 一.文件 ...
- Java Web文件上传原理分析(不借助开源fileupload上传jar包)
Java Web文件上传原理分析(不借助开源fileupload上传jar包) 博客分类: Java Web 最近在面试IBM时,面试官突然问到:如果让你自己实现一个文件上传,你的代码要如何写,不 ...
- Struts2单文件上传原理及示例
一.文件上传的原理 表单元素的enctype属性指定的是表单数据的编码方式,该属性有3个值: 1.application/x-www-form-urlencoded:这是默认编码方式,它只处理表单域里 ...
- 常见的文件上传方法有哪些?Ajax文件上传原理是什么?
Ajaxfileupload,Ajaxupload,JqueryUploadify无刷新式的文件上传,在一个页面里嵌入一个Iframe,然后在Iframe使用原生的Post表单提交.
- js文件上传原理(form表单 ,FormData + XHR2 + FileReader + canvas)
目录 form表单上传 FormData + XHR2 + FileReader + canvas 无刷新本地预览压缩上传实例 目前实现上传的方式 浏览器小于等于IE9(低版本浏览器)使用下面的方式实 ...
- Struts2多文件上传原理和示例
一.创建上传文件的页面,代码如下所示 1.Struts2也可以很方便地实现多文件上传. 在输入表单域增加多个文件域:multifileupload.jsp <%@ page lan ...
- HTTP上传 文件上传 图片上传 HTTP上传原理 文件上传原理 图片上传原理
1.概述 在最初的http协议中,没有上传文件方面的功能.rfc1867(http://www.ietf.org/rfc/rfc1867.txt )为http协议添加了这个功能.浏览器按照此规范将用户 ...
随机推荐
- PWN菜鸡入门之栈溢出 (2)—— ret2libc与动态链接库的关系
准备知识引用自https://www.freebuf.com/articles/rookie/182894.html 0×01 利用思路 ret2libc 这种攻击方式主要是针对 动态链接(Dynam ...
- Appium+python自动化(十一)- 元素定位秘籍助你打通任督二脉 - 下卷(超详解)
简介 宏哥看你骨骼惊奇,印堂发亮,必是练武之奇才! 按照上一篇的节目预告,这一篇还是继续由宏哥给小伙伴们分享元素定位,是不是按照上一篇的秘籍修炼,是不是感觉到头顶盖好像被掀开,内气从头上冒出去,顿时觉 ...
- mysql5.7 group by语法 1055
先来看如下语句,查询默认存在的引擎表 之前使用的MySQL版本为5.7以下,根据support进行分组执行语句如下 添加跟分组support无关的字段engine 没有任何问题 现在使用的版本是5.7 ...
- Linux系统下解锁Oracle的Scott用户
1).在Oracle用户下面输入命令:lsnrctl status查看监听是否开启,如果未开启则需要开启监听,输入命令:lsnrctl start; 2).如果没有设置监听的话需要先建立一个监听,然后 ...
- Java学习笔记——设计模式之七.模板方法模式
模板方法模式(TemplateMethod),定义一个操作中的算法的骨架,而将一些步骤延迟到子类中.模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤. 结构图: 代码: 算法骨架 ...
- tar命令中的 -C 作用
我用这个命令:tar zcvf chao.tar.gz /chao/* 打包文件的时候,在压缩包里把 /chao/这个路径也打包进去了. [root@yunwei-test chao]# ls / ...
- SQL 对float类型列进行排序引发的异常
车祸现场 要求:根据学分和完成时间获取前200名学员,当学分相同时,完成时间较早的排在前面 可以明显看到,完成时间为4.1号的记录排在了3.27号前面. 事故原因 float 表示近似数值,存在精度损 ...
- Codeforces 1133E - K Balanced Teams - [DP]
题目链接:https://codeforces.com/contest/1133/problem/C 题意: 给出 $n$ 个数,选取其中若干个数分别组成 $k$ 组,要求每组内最大值与最小值的差值不 ...
- 安装Win10,ERROR_0x8007025D问题解决
Windows10安装的时候,出现ERROR CODE:0x8007025D 大概提示为:windows 无法安装所需的文件.请确保安装所需的所有文件可用,并重新启动安装. 本人在出现这个问题的原因, ...
- Linux命令学习-ls命令
Linux中,ls命令的全称是list,主要作用是列出当前目录下的清单. 列出Linux根目录下的所有目录 ls / 列出当前目录下所有文件夹和文件 ls 列出当前目录下所有文件夹和文件(包括以&qu ...