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协议添加了这个功能.浏览器按照此规范将用户 ...
随机推荐
- 丢给你一个txt并同时获取你shell
丢给你一个txt并同时获取你shell 0x00:回顾 <文本编辑器Vim/Neovim被曝任意代码执行漏洞> 听闻很多人知道这个漏洞,但是有一部分人能复现成功,一部分人复现不出来.这里我 ...
- java基础知识总结(二)
Java中的代码块 java中的代码块是用{}括起来的代码,进行一些功能的限定 静态代码块:在类第一次被初始化的是后执行,负责一些类的初始化操作,仅仅只执行一次 构造代码块:顾名思义,辅助构造器进行初 ...
- CI框架使用(一)
CI框架的使用是很简单,也 是mvc模式.其中有好多类直接调用. 在使用帮助函数的时候,都需要手动加载,或者是在配置文件中加一个自动加载 $this->load->helper('ur ...
- Linux搭建基于Apache的HTTP服务器
Linux搭建基于Apache的HTTP服务器 实验目标: 通过本实验掌握基于Linux的WWW服务器搭建. 实验步骤: 1.安装http服务 2.防火墙放通http服务 3.编辑测试网页 4.开 ...
- 2018.10.20 2018NOIP冲刺之酒厂选址
题目传送门 明显能够看出有一个建图求路程的优化 然而发现10000*10000爆空间QAQ 为了做一些初始化方面的优化 我们发现了一个叫做前缀和的东西 可以在环上查到两个之间的最短距离 同时还要做一些 ...
- POJ 3692:Kindergarten(二分图最大团)
题目链接 题意 已知班级有g个女孩和b个男孩,所有女生之间都相互认识,所有男生之间也相互认识,给出m对关系表示哪个女孩与哪个男孩认识.现在要选择一些学生来组成一个集合,使得里面所有人都认识,求此集合最 ...
- java html中文汉字 反转义
import org.apache.commons.lang.StringEscapeUtils; public class EscapeHtml { /** * @param args */ pub ...
- 聚类时的轮廓系数评价和inertia_
在进行聚类分析时,机器学习库中提供了kmeans++算法帮助训练,然而,根据不同的问题,需要寻找不同的超参数,即寻找最佳的K值 最近使用机器学习包里两个内部评价聚类效果的方法:clf=KMeans(n ...
- 【Aizu - 0121】Seven Puzzle (反向bfs)
-->Seven Puzzle 原文是日语 这里就直接写中文了 Descriptions: 7拼图由8个正方形的卡和这些卡片完全收纳的框构成.每张卡都编号为0, 1, 2, …, 7,以便相互 ...
- C++学习书籍推荐《Effective C++ 第三版》下载
百度云及其他网盘下载地址:点我 编辑推荐 <Effective C++:改善程序与设计的55个具体做法(第3版)(中文版)(双色)>前两个版本抓住了全世界无数程序员的目光.原因十分明显:S ...