表单提交 multipart/form-data 和 x-www-form-urlencoded的区别
表单提交
表单有两种提交方式,POST和GET。通常我们会使用POST方式,一是因为形式上的安全 ;二是可以上传文件。
我之前经常忽略掉表单的编码类型,觉得它特别长比较难记,而且不设置也似乎不影响什么。表单的编码类型,用来控制表单中的数据的编码格式。POST 提交方式 默认 enctype=“application/x-www-form-urlencoded”,数据以键值对的方式传送到服务器,这种方式适合于大多数场景。GET 提交方式,默认none。
表单(POST请求)支持下面两种编码:
enctype
application/x-www-form-urlencoded 不指定时默认方式, key1=value1&key2=value2
multipart/form-data 一般用于表单需要文件上传
表单(GET请求)支持下面两种编码:
enctype
application/x-www-form-urlencoded key1=value1&key2=value2
none 不指定时默认方式,getContentType() 返回null
ServletRequest中获取参数常用方法:
Map<String,String[]> maps= request.getParameterMap(); //获取所有的键值对
Enumeration<String> names= request.getParameterNames();//获取所有的参数名
String[] values = request.getParameterValues(parameterName); //获取某个参数下的所有值,适合多选组件
String value = request.getParameter(parameterName); //获取某个参数对应的值,适合文本组件,单选等
ServletInputStream stream=request.getInputStream();//需要注意的是,该方法只能被调用一次,再次调用返回结果为空
BufferedReader reader=request.getReader();//该方法也是只能调用一次
Collection<Part> parts = request.getParts();// 获取 multipart/form-data 编码方式的数据
需要额外注意的是:getInputStream 方法和getReader方法互斥。最多只能调用其中的一个,如果这两个方法都被调用则会抛出异常。
request.getInputStream();//需要注意的是,该方法只能被调用一次,再次调用返回结果为空
request.getReader();//该方法也是只能调用一次
1.application/x-www-form-urlencoded
- GET方式,会将表单中的数据(键值对)经过urlencode编码后追加到url中。
- POST方式,会将表单中的数据经过urlencode编码后放在request body 中。
<form action="/xxxx" method="post" enctype="application/x-www-form-urlencoded">
name: <input type="text" name="name"><br>
password: <input type="text" name="password"><br>
<input type="submit" value="提交">
</form>POST 提交方式: name 传递 “测试人”,password 传递“test”.(postman 工具测试结果)
Content-Type: application/x-www-form-urlencoded name:%E6%B5%8B%E8%AF%%E4%BA%BA
password:test该编码方式,会将表单数据中的非西欧字符转化为十六进制数字的形式。utf8字符集中,每个汉字占3个字节,每个汉字会转化成3个十六进制的数 %XX%XX%XX 的形式。
在java 代码中经常会处理下载文件名中文乱码的问题,对于IE,谷歌等浏览器用到的就是编码方式。
try {
System.out.println(URLEncoder.encode("测试人","UTF8"));
//%E6%B5%8B%E8%AF%95%E4%BA%BA
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}当然浏览器不同使用的处理编码也不尽相同。在使用Chrome的话显示如下(gb2312编码),这个可能和当前使用的语言环境有关:
name: %B2%E2%CA%D4%C8%CB
password: test接下来就是获取值
Map<String,String[]> maps= request.getParameterMap(); //获取所有的键值对
Enumeration<String> names= request.request.getParameterNames();//获取所有的参数名
String[] values = request.getParameterValues(parameterName); //获取某个参数下的所有值,适合多选组件
String value = request.getParameter(parameterName); //获取某个参数对应的值,适合文本组件,单选等如果需要在表单中上传文件则不能使用该方式
2.multipart/form-data
当需要在表单内上传文件时(二进制流数据)时,就需要使用 multipart/form-data。
<form action="/xxxx" method="POST" enctype="multipart/form-data">
<label>手机号</label><input type="text" name="phone"><br>
<label>邮箱</label> <input type="text" name="mail"><br>
<label>头像</label><input type="file" name="portrait"><br/>
<input type="submit" value="提交">
</form>
请求行的部分内容
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW
请求体的内容
------WebKitFormBoundary7MA4YWxkTrZu0gW
Content-Disposition: form-data; name=“phone” ------WebKitFormBoundary7MA4YWxkTrZu0gW
Content-Disposition: form-data; name=“mail”
test@.com
------WebKitFormBoundary7MA4YWxkTrZu0gW
Content-Disposition: form-data; name="portrait "; filename=“portrait.png”
Content-Type: image/png
------WebKitFormBoundary7MA4YWxkTrZu0gW–
multipart,顾名思义 多部分。使用该编码方式会将表单进行分割成每个控件(以----boundary为分隔符,将分割控件数据分隔开,在最后以—boundary—结尾)。每个部分必须加上Content-Disposition(form-data) ,对于上传文件还会设置Content-Type。
对于上传的不同类型的文件,会自动识别文件类型,如果识别不了则设置为application/octet-stream。
上传jpeg格式图片
Content-Type: image/jpeg
上传pdf文件
Content-Type: application/pdf
上传MP3
Content-Type: audio/mp3
对于使用该方式提交的表单,在服务器端的参数获取通常有以下两种:
单独获取 键值对数据。 使用getParameterMap() ,getParameter()等常规方法获取数据
获取全部数据(键值对和二进制流) getParts()。
使用getParts()方法,要求Content-Type:multipart/form-data,否则抛出异常。
通过Part 获取上传的文本内容
System.out.println(request.getParameter("phone"));
System.out.println(request.getParameter("mail"));
System.out.println(request.getParameter("portrait"));//二进制数据返回null
System.out.println("----------------getParts获取参数-------------------------");
//如果是multipart/form-data 提交方式,则此时 contentType:multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW
String contentType=request.getContentType(); if(contentType !=null && contentType.contains(MediaType.MULTIPART_FORM_DATA_VALUE)) {//判断是否是multipart/form-data 提交方式
Collection<Part> parts = request.getParts(); //获取所有的部分
for(Part part :parts) {
System.out.println(part.getContentType());
InputStream inPart = part.getInputStream();
String name=part.getName();//请求名称
StringBuilder buffer=new StringBuilder(); //保存请求值
byte[] buff =new byte[];
int length=;
while((length=inPart.read(buff))!=-) {
buffer.append(new String(buff,,length,"utf8"));
}
System.out.println("name = "+name+"\tvalue="+buffer);
}
}
输出结果
test@.com
null
----------------getParts获取参数-------------------------
null
name = phone value=
null
name = mail value=test@.com
image/png
name = portrait value=�PNG
图片比较大,所以只截取了一点。
注意:
在判断contentType时,multipart/form-data提交方式的contentType不单纯是multipart/form-data,还会包含 boundary=----WebKitFxxxx
小结
使用不同的编码方式,服务端获取参数的方式也不尽相同。
application/x-www-form-urlencoded。 该方式就是常规的方法, getParameterMap(),getParameter()等方式获取参数
multipart/form-data
号 | 键值对 | 二进制数据 |
---|---|---|
1 | getParameter(),getParameterMap | getParts(); |
2 | getParts() |
注意: 使用 getParts() 方法 必须保证 ContentType 包含 ”multipart/form-data“ ,否则抛出ServletException,如果上传文件特别大则会抛出IllegalStateException
重复说明:
getReader()和getInputSteam()互斥
getReader()和getInputStream() 只能调用一次
补充
在使用elasticsearch 的时候,发现 GET请求可以有请求体。当时就很懵逼,查阅资料后发现http标准中 GET请求确实可以有请求体。之前使用POSTMAN的时候都没有注意过,也是心大了。
请求体的编码方式和POST请求一致,但是GET方式请求体可以传输的数据要远小于POST 请求的。
enctype | GET 请求获取数据 | POST 请求获取数据 | |
application/x-www-form-urlencoded | getInputStream() | getParameter() | |
multipart/form-data getInputStream() | getParameter() | getParameter(), getParts() | |
raw | 比如常用的 ajax请求 application/json | getInputStream() | getInputStream() |
binary | 文件类型 | getInputStream() | getInputStream() |
注意:
1. getInputStream() 不限 getInputStream方式,还包括 getReader()
2. getParameter() 方式还包括 getParameterMap(),getParameterValues(),getParameterNames()
3. multipart/form-data 类型的请求体, GET请求的数据不能通过getParts()获取
测试发现,虽然GET请求可以使用上面的几种方式。但是请求体中的内容只能通过 getInputStram()等流式方式获取。
文本
可以指定的文本内容格式有多种,application/json是最常用的
text/plain: 纯文本
text/xml :传递xml语法格式的字符串
text/html: 传递html字符串
application/json : 传递序列化后的 JSON 字符串。
获取数据
ServletInputStream in = request.getInputStream();//该方法也是只能调用一次
BufferedReader reader=request.getReader();//该方法也是只能调用一次
文本数据格式,会使用流的方式传递数据。在springmvc中使用@RequestBody注解对应的注解解释类应该就是通过InputSteam获取数据并转化为json对象。
表单提交 multipart/form-data 和 x-www-form-urlencoded的区别的更多相关文章
- js实现无刷新表单提交文件,将ajax请求转换为form请求方法
最近在做项目的时候遇到一个需要上传文件的需求,因为ajax请求是无法上传二进制文件流的,所以只能用form表单提交,而form提交有一个问题就是会使页面刷新,本文解决了form表单提交文件时页面刷新的 ...
- jQuery Form 表单提交插件-----formSerialize,fieldSerialize,fieldValue,resetForm,clearForm,clearFields的 应用
一.jQuery Form的其他api 1. formSerialize 将表单序列化成查询串.这个方法将返回一个形如: name1=value1&name2=value2的字符串.是否可 ...
- 怎么实现form表单提交后不重新刷新当前页面
怎么实现表单提交后不重新刷新当前页面 如何实现表单提交后不重新刷新当前页面 <form name='form1' id='form1' action='/xbcw/cw/xx_xx.ac ...
- php form表单提交时,action url中参数无效的解决方法
表单提交时get方式的一个错误 <form class="form-inline pull-right" method="get" action=&quo ...
- HTML5:表单提交
不加CSS.JavaScrips的HTML表单提交简单代码 <!DOCTYPE html> <html lang="en"> <head> &l ...
- 利用JS 阻止表单提交
情景一:不存在Ajax异步操作 1 使用背景:会议室预定管理系统中,当表单提交的时候需要验证预约的时间是否符合预定规则(不需要通过访问服务器),否则提示错误信息,阻止表单提交. 2 相关技术点: fo ...
- JSP将表单提交并在本页中显示
代码如下: <%@ page language="java" import="java.util.*" pageEncoding="UTF-8& ...
- 黄聪:Pjax无刷新跳转页面实现,支持超链接与表单提交
什么是pjax? 当你点击一个站内的链接的时候,不是做页面跳转,而是只是站内页面刷新.这样的用户体验,比起整个页面都闪一下来说, 好很多. 其中有一个很重要的组成部分, 这些网站的ajax刷新是支持浏 ...
- Pjax无刷新跳转页面实现,支持超链接与表单提交
什么是pjax? 当你点击一个站内的链接的时候,不是做页面跳转,而是只是站内页面刷新.这样的用户体验,比起整个页面都闪一下来说, 好很多. 其中有一个很重要的组成部分, 这些网站的ajax刷新是支持浏 ...
随机推荐
- python3学习笔记(二):Python初识
一.算法 在开始认真地编程之前,首先来解释下什么是计算机程序设计.简单地说,它就是告诉计算机要做什么.计算机可以做很多事情,但是它不会自己思考,需要我们告诉它具体细节,并且使用计算机能够理解的语言把算 ...
- (76)深入浅出Mqtt协议
物联网(Internet of Things,IoT)时代机器之间(Machine-to-Machine,M2M)的大规模沟通需要发布/订阅(Publish/Subscribe)模式,轻量级.易扩展的 ...
- ApiException
ApiException 用于在catch中throw 异常,可以添加异常信息, throw new ApiException("线下绑卡异常!"); public class A ...
- Spring Boot教程(十四)快速入门
快速入门 本章主要目标完成Spring Boot基础项目的构建,并且实现一个简单的Http请求处理,通过这个例子对Spring Boot有一个初步的了解,并体验其结构简单.开发快速的特性. 系统要求: ...
- 关于TCP/IP,必须知道的十个知识点(转)
三次握手四次挥手可参考:http三次握手,四次挥手 本文整理了一些TCP/IP协议簇中需要必知必会的十大问题,既是面试高频问题,又是程序员必备基础素养. 一.TCP/IP模型 TCP/IP协议模型(T ...
- List of Mozilla-Based Applications
List of Mozilla-Based Applications The following is a list of all known active applications that are ...
- Python 字符串与列表去重
最近面试中出现频率比较高的字符串和列表的去重pstr = 'abcadcf'# 字符串去重# 1.使用集合 --没有保持原来的顺序 print(set(pstr)) # 2.使用字典 -- 没有保持原 ...
- 对vi/vim的一些看法
早在网上看到别人如何把vi吹得神乎其神了,决定试着用一下.不过还是发现太麻烦了,因为我是在windows系统下面的,网络的原因无法使用linux系统(无校园电信客户端). 首先vim只是一个文本编辑器 ...
- gunicorn+nginx配置方法
对于gunicorn+nginx的配置,理解他们之间的关系很重要,以及最后如何确认配置结果是正确的也很重要 nginx 配置文件: 修改这个配置文件有3个用处: 假设服务器本身的Ip是A称为ip-A, ...
- mysql 批量删表
Select CONCAT( 'drop table ', table_name, ';' ) FROM information_schema.tables Where table_name LIKE ...