HTTP POST 请求的两种编码格式:application/x-www-form-urlencoded 和 multipart/form-data
在常见业务开发中,POST 请求常常在这些地方使用:前端表单提交时、调用接口代码时和使用 Postman 测试接口时。我们下面来一一了解:
一、前端表单提交时
application/x-www-form-urlencoded
表单代码:
<form action="http://localhost:8888/task/" method="POST">
First name: <input type="text" name="firstName" value="Mickey&"><br>
Last name: <input type="text" name="lastName" value="Mouse "><br>
<input type="submit" value=" 提交 ">
</form>
通过测试发现可以正常访问接口,在 Chrome 的开发者工具中可以看出,表单上传编码格式为 application/x-www-form-urlencoded(Request Headers 中),参数的格式为 key=value&key=value。

我们可以看出,服务器知道参数用符号 & 间隔,如果参数值中需要 &,则必须对其进行编码。编码格式就是 application/x-www-form-urlencoded(将键值对的参数用 & 连接起来,如果有空格,将空格转换为 + 加号;有特殊符号,将特殊符号转换为 ASCII HEX 值)。
application/x-www-form-urlencoded 是浏览器默认的编码格式。对于 Get 请求,是将参数转换 ?key=value&key=value 格式,连接到 url 后
ps:可以在这个网址测试表单:http://www.runoob.com/try/try.php?filename=tryhtml_form_submit
multipart/form-data
那么当服务器使用 multipart/form-data 接收 POST 请求时,服务器怎么知道每个参数的开始位置和结束位置呢?
<form action="http://localhost:8888/task/" method="POST" enctype="multipart/form-data">
First name: <input type="text" name="firstName" value="Mickey&"><br>
Last name: <input type="text" name="lastName" value="Mouse "><br>
<input type="submit" value=" 提交 ">
</form>
我们在开发者工具中可以看出 multipart/form-data 不会对参数编码,使用的 boundary(分割线),相当于 &,boundary 的值是 ----Web*AJv3。

文件上传
上传文件也要指定编码格式为 multipart/form-data。
<form action="http://localhost:8888/testFile" enctype="multipart/form-data" method="POST">
<input type="file" name="file">
<input type="submit" value=" 提交 ">
</form>
如果是 SpringMVC 项目,要服务器能接受 multipart/form-data 类型参数,还要在 spring 上下文配置以下内容,SpringBoot 项目则不需要。
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="defaultEncoding" value="utf-8"></property>
</bean>
我们可以通过 FormData 对象模拟表单提交,用原始的 XMLHttpRequest 来发送数据,让我们可以在 Chrome 开发工具中查看到具体格式:
<form id="form">
First name: <input type="text" name="firstName" value="Mickey"><br>
Last name: <input type="text" name="lastName" value="Mouse"><br>
<input type="file" name="file"><br>
</form>
<button onclick="submitForm()"> 提交 </button>
<script>
function submitForm() {
var formElement = document.getElementById("form");
var xhr = new XMLHttpRequest();
xhr.open("POST", "/task/testFile");
xhr.send(new FormData(formElement));
}
</script>
格式如下:

二、调用接口代码时
1、在代码中使用 application/x-www-form-urlencoded 编码格式设置 Request 属性调用接口,可以如下实现:
private static String doPost(String strUrl, String content) {
String result = "";
try {
URL url = new URL(strUrl);
// 通过调用 url.openConnection() 来获得一个新的 URLConnection 对象,并且将其结果强制转换为 HttpURLConnection.
HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
urlConnection.setRequestMethod("POST");
// 设置连接的超时值为 30000 毫秒,超时将抛出 SocketTimeoutException 异常
urlConnection.setConnectTimeout(30000);
// 设置读取的超时值为 30000 毫秒,超时将抛出 SocketTimeoutException 异常
urlConnection.setReadTimeout(30000);
// 将 url 连接用于输出,这样才能使用 getOutputStream()。getOutputStream() 返回的输出流用于传输数据
urlConnection.setDoOutput(true);
// 设置通用请求属性为默认浏览器编码类型
urlConnection.setRequestProperty("content-type", "application/x-www-form-urlencoded");
//getOutputStream() 返回的输出流,用于写入参数数据。
OutputStream outputStream = urlConnection.getOutputStream();
outputStream.write(content.getBytes());
outputStream.flush();
outputStream.close();
// 此时将调用接口方法。getInputStream() 返回的输入流可以读取返回的数据。
InputStream inputStream = urlConnection.getInputStream();
byte[] data = new byte[1024];
StringBuilder sb = new StringBuilder();
//inputStream 每次就会将读取 1024 个 byte 到 data 中,当 inputSteam 中没有数据时,inputStream.read(data) 值为 - 1
while (inputStream.read(data) != -1) {
String s = new String(data, Charset.forName("utf-8"));
sb.append(s);
}
result = sb.toString();
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
return result;
}
public static void main(String[] args) {
String str = doPost("http://localhost:8888/task/", "firstName=Mickey%26&lastName=Mouse ");
System.out.println(str);
}
2、在代码中使用 multipart/form-data 编码格式设置 Request 属性调用接口时,其中 boundary 的值可以在设置 Content-Type 时指定,让服务器知道如何拆分它接受的参数。通过以下代码的调用接口:
private static String doPost(String strUrl, Map<String, String> params, String boundary) {
String result = "";
try {
URL url = new URL(strUrl);
HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
urlConnection.setRequestMethod("POST");
urlConnection.setConnectTimeout(30000);
urlConnection.setReadTimeout(30000);
urlConnection.setDoOutput(true);
// 设置通用请求属性为 multipart/form-data
urlConnection.setRequestProperty("content-type", "multipart/form-data;boundary=" + boundary);
DataOutputStream dataOutputStream = new DataOutputStream(urlConnection.getOutputStream());
for (String key : params.keySet()) {
String value = params.get(key);
// 注意!此处是 \r(回车:将当前位置移到本行开头)、\n(换行:将当前位置移到下行开头) 要一起使用
dataOutputStream.writeBytes("--" + boundary + "\r\n");
dataOutputStream.writeBytes("Content-Disposition: form-data; name=\"" + encode(key) + "\"\r\n");
dataOutputStream.writeBytes("\r\n");
dataOutputStream.writeBytes(encode(value) + "\r\n");
}
// 最后一个分隔符的结尾后面要跟 "--"
dataOutputStream.writeBytes("--" + boundary + "--");
dataOutputStream.flush();
dataOutputStream.close();
InputStream inputStream = urlConnection.getInputStream();
byte[] data = new byte[1024];
StringBuilder sb = new StringBuilder();
while (inputStream.read(data) != -1) {
String s = new String(data, Charset.forName("utf-8"));
sb.append(s);
}
result = sb.toString();
inputStream.close();
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
private static String encode(String value) throws UnsupportedEncodingException {
return URLEncoder.encode(value, "UTF-8");
}
public static void main(String[] args) {
Map<String, String> params = new HashMap<>();
params.put("firstName", "Mickey");
params.put("lastName", "Mouse");
// 自定义 boundary,有两个要求:使用不会出现在发送到服务器的 HTTP 数据中的值;并在请求消息中的分割位置都使用相同的值
String boundary = "abcdefg";
String str = doPost("http://localhost:8888/testFile", params, boundary);
System.out.println(str);
}
通过 debug,可以看出 dataOutputStream 的值如下:

三、使用 Postman 测试接口时
1、POST 请求 -> Body -> x-www-form-urlencoded

当切换为 x-www-form-urlencoded 时,Headers 会自动添加 Content-Type:application/x-www-form-urlencoded

当请求 Send 后,此时点 Code,可以查看到和 Chrome 开发工具中 (Request Headers 处的 Content-Type 和 Form Data) 一样的数据

2、POST 请求 -> Body -> form-data
相当于 html 表单请求,value 可为 Text 或文件。

可以不用手动指定编码格式,也可以指定编码为 multipart/form-data

划线处的分割线应该是被省略了。

可以更改左上角的类型,来查看相应的 Headers 代码,常见的是下面三种:
Java OK HTTP:

JavaScript Jquery AJAX:

JavaScript XHR:

接口代码
@RequestMapping("/task")
public class TaskController {
@RequestMapping("/")
public String index(String firstName, String lastName) {
return firstName + lastName;
}
@RequestMapping("/testFile")
public String testFile(String firstName, String lastName, MultipartFile file) {
String result = firstName + lastName;
if (file != null) {
result += (file.getOriginalFilename() != null) ? file.getOriginalFilename() : "";
}
return result;
}
}
总结
POST 请求的两种编码格式:application/x-www-urlencoded 是浏览器默认的编码格式,用于键值对参数,参数之间用 & 间隔;multipart/form-data 常用于文件等二进制,也可用于键值对参数,最后连接成一串字符传输 (参考 Java OK HTTP)。除了这两个编码格式,还有 application/json 也经常使用。
延伸阅读
HTTP POST 请求的两种编码格式:application/x-www-form-urlencoded 和 multipart/form-data的更多相关文章
- Post请求的两种编码格式:application/x-www-form-urlencoded和multipart/form-data
在常见业务开发中,POST请求常常在这些地方使用:前端表单提交时.调用接口代码时和使用Postman测试接口时.我们下面来一一了解: 一.前端表单提交时 application/x-www-form- ...
- C#中Post请求的两种方式发送参数链和Body的
POST请求 有两种方式 一种是组装key=value这种参数对的方式 一种是直接把一个字符串发送过去 作为body的方式 我们在postman中可以看到 sfdsafd sdfsdfds publi ...
- .net中对HTTP请求的两种请求:Get和Post的操作
.net中对HTTP请求的简单操作总结 第一部分,HTTP协议的简单了解 一. 什么是HTTP协议 超文本传输协议 (HTTP-Hypertext transfer protoco ...
- 第二节:SSL证书的申请、配置(IIS通用)及跳转Https请求的两种方式
一. 相关概念介绍 1. SSL证书服务 SSL证书服务由"服务商"联合多家国内外数字证书管理和颁发的权威机构.在xx云平台上直接提供的服务器数字证书.您可以在阿里云.腾讯云等平台 ...
- 解决 SharePoint 2010 拒绝访问爬网内容源错误的小技巧(禁用环回请求的两种方式)
这里有一条解决在SharePoint 2010搜索爬网时遇到的“拒绝访问错误”的小技巧. 首先要检查默认内容访问帐户是否具有相应的访问权限,或者添加一条相应的爬网规则.如果目标资源库是一个ShareP ...
- iOS- 网络请求的两种常用方式【GET & POST】的区别
GET和POST 网络请求的两种常用方式的实现[GET & POST] –GET的语义是获取指定URL上的资源 –将数据按照variable=value的形式,添加到action所指向的URL ...
- GET和POST是HTTP请求的两种基本方法,区别是什么!?
GET和POST是HTTP请求的两种基本方法,要说它们的区别,接触过WEB开发的人都能说出一二. 最直观的区别就是GET把参数包含在URL中,POST通过request body传递参数. 你可能自己 ...
- CAN总线常见的两种编码格式(Intel/Motorola)
在汽车电子行业的开发或者测试中,我们经常会看到CAN总线信号的常见的两种编码格式:Intel格式与Motorola格式. 讲解这两种格式之前,我们先来了解一些大端模式和小端模式,会对后面理解这两种编码 ...
- ASP.NET MVC 实现AJAX跨域请求的两种方法
通常发送AJAX请求都是在本域内完成的,也就是向本域内的某个URL发送请求,完成部分页面的刷新.但有的时候需要向其它域发送AJAX请求,完成数据的加载,例如Google. 在ASP.NET MVC 框 ...
随机推荐
- 数据可视化基础专题(五):Pandas基础(四) 生成对象
引言 先介绍下 Pandas 的数据结构,毕竟数据结构是万物的基础. Pandas 有两种主要的数据结构: Series 和 DataFrame 模块导入 首先我们在代码中引入 Pandas 和 Nu ...
- Drf06 /drf总结
Drf06 /drf总结 目录 Drf06 /drf总结 1. restful规范 2. drf组件认证的实现过程? 3. drf组件中权限的实现过程? 4. drf组件中节流的实现方式? 5. 什么 ...
- bzoj3043IncDec Sequence*
bzoj3043IncDec Sequence 题意: n个数,每次可以将区间l到r里的数+1或-1,问将它们变成同个数的最小操作次数和保证最小操作次数前提下有多少中可能.n≤100000. 题解: ...
- 读取文件夹内容解析为Tree结构
package com.mine.io; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONArray; import ...
- 【python大牛分享】python——接口自动化测试框架环境的使用
本文总结分享介绍接口测试框架开发,环境使用python3+selenium3+unittest+ddt+requests测试框架及ddt数据驱动,采用Excel管理测试用例等集成测试数据功能,以及使用 ...
- PyQt5主界面
QMainWindow QMainWindow控件继承之QWidget控件,QWidget是所有控件的父类,主要提供界面的基本功能,包括边框.标题.工具栏.关闭按钮.最小化按钮以及最大化按钮等.子类中 ...
- 使用ImpromptuInterface反射库方便的创建自定义DfaGraphWriter
在本文中,我为创建的自定义的DfaGraphWriter实现奠定了基础.DfaGraphWriter是公开的,因此您可以如上一篇文章中所示在应用程序中使用它,但它使用的所有类均已标记为internal ...
- GitHub 热点速览 Vol.29:程序员资料大全
作者:HelloGitHub-小鱼干 摘要:有什么资料比各种大全更吸引人的呢?先马为敬,即便日后"挺尸"收藏夹,但是每个和程序相关的大全项目都值得一看.比如国内名为小傅哥整理的 J ...
- Go语言基础语法总结
1. 认识HelloWorld 在前面的<Go的安装和使用>这篇文章中已经写过HelloWorld.go了,现在就来逐行认识一下它. package main import "f ...
- SQL之DDL、DML、DCL、TCL
SQL SQL(structured query language)是一种领域特定语言(DSL,domain-specific language),用于管理关系型数据库(relational data ...