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协议添加了这个功能.浏览器按照此规范将用户 ...
随机推荐
- webapi使用autofac
注意:您的项目中如果使用的是webapi2,此处必须为webapi2而不是webapi,否则在运行时将出现“重写成员“Autofac.Integration.WebApi.AutofacWebApiD ...
- Git 所有常用命令
写的很细致,存: https://blog.csdn.net/Mr_Lewis/article/details/85547057
- Requests方法 -- 重定向操作
一.重定向1. (Redirect)就是通过各种方法将各种网络请求重新定个方向转到其它位置,从地址A跳转到地址 B 了.2.重定向状态码:--301 redirect: 301 代表永久性转移(Per ...
- C# 死锁 Task/AutoResetEvent
与之前<C# 死锁 TaskCompletionSource>类似,还有很多死锁的案例 使用Task异步转同步时,使用不当造成的死锁 private void Task_OnClick(o ...
- C++ 洛谷 P2704 [NOI2001]炮兵阵地
P2704 [NOI2001]炮兵阵地 没学状压DP的看一下 此题意思很简单,如下图,就是十字架上的不能有两个点放炮兵. 在做此题前,先做一下玉米田 玉米田题解 分析: 而m即一行的个数小于等于10, ...
- Linux权限_用户_和用户组
Linux中用户UID就判断操作系统中用户的身份. Centos7.x: 0:超级管理员 1-999:系统用户(包含Linux中自带服务) 1000以上 普通用户 Centos6.x : Root ...
- C++学习书籍推荐《Effective C++ 第三版》下载
百度云及其他网盘下载地址:点我 编辑推荐 <Effective C++:改善程序与设计的55个具体做法(第3版)(中文版)(双色)>前两个版本抓住了全世界无数程序员的目光.原因十分明显:S ...
- [NOIP2009]靶形数独 题解
407. [NOIP2009] 靶形数独 时间限制:5 s 内存限制:128 MB [问题描述] 小城和小华都是热爱数学的好学生,最近,他们不约而同地迷上了数独游戏,好胜的他们想用数独来一比高低. ...
- 【小家Spring】Spring IoC是如何使用BeanWrapper和Java内省结合起来给Bean属性赋值的
#### 每篇一句 > 具备了技术深度,遇到问题可以快速定位并从根本上解决.有了技术深度之后,学习其它技术可以更快,再深入其它技术也就不会害怕 #### 相关阅读 [[小家Spring]聊聊Sp ...
- Linux系统-CENTOS7界面美化
前期准备: 在美化前,我们先安装一个扩展源. yum install -y epel-release 然后安装字体包 yum -y install liberation-mono-fonts 安装gn ...