知识就是力量,时间就是生命。这篇文章主要讲述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="https://www.songbingjia.com/android/Mickey&">
<
br>
Last name: <
input type="text" name="lastName" value="https://www.songbingjia.com/android/Mouse">
<
br>
<
input type="submit" value="https://www.songbingjia.com/android/提交">
<
/form>
通过测试发现可以正常访问接口,在Chrome的开发者工具中可以看出,表单上传编码格式为
application/x-www-form-urlencoded
(Request Headers中),参数的格式为key=value&
key=value
。文章图片
image.png我们可以看出,服务器知道参数用符号
&
间隔,如果参数值中需要&
,则必须对其进行编码。编码格式就是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="https://www.songbingjia.com/android/Mickey&">
<
br>
Last name: <
input type="text" name="lastName" value="https://www.songbingjia.com/android/Mouse">
<
br>
<
input type="submit" value="https://www.songbingjia.com/android/提交">
<
/form>
我们在开发者工具中可以看出
multipart/form-data
不会对参数编码,使用的boundary
(分割线),相当于&
,boundary
的值是----Web**AJv3
。文章图片
image.png文件上传上传文件也要指定编码格式为
multipart/form-data
。<
form action="http://localhost:8888/testFile" enctype="multipart/form-data" method="POST">
<
input type="file" name="file">
<
input type="submit" value="https://www.songbingjia.com/android/提交">
<
/form>
如果是SpringMVC项目,要服务器能接受
multipart/form-data
类型参数,还要在spring上下文配置以下内容,SpringBoot项目则不需要。<
bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<
property name="defaultEncoding" value="https://www.songbingjia.com/android/utf-8">
<
/property>
<
/bean>
我们可以通过FormData对象模拟表单提交,用原始的XMLHttpRequest来发送数据,让我们可以在Chrome开发工具中查看到具体格式:
<
form id="form">
First name: <
input type="text" name="firstName" value="https://www.songbingjia.com/android/Mickey">
<
br>
Last name: <
input type="text" name="lastName" value="https://www.songbingjia.com/android/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>
格式如下:
文章图片
image.png二、调用接口代码时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 = https://www.songbingjia.com/android/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 = https://www.songbingjia.com/android/params.get(key);
//注意!此处是
(回车:将当前位置移到本行开头)、
(换行:将当前位置移到下行开头)要一起使用
dataOutputStream.writeBytes("--" + boundary + "");
dataOutputStream.writeBytes("Content-Disposition: form-data;
name="" + encode(key) + """);
dataOutputStream.writeBytes("");
dataOutputStream.writeBytes(encode(value) + "");
}
//最后一个分隔符的结尾后面要跟"--"
dataOutputStream.writeBytes("--" + boundary + "--");
dataOutputStream.flush();
dataOutputStream.close();
InputStream inputStream = urlConnection.getInputStream();
byte[] data = https://www.songbingjia.com/android/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的值如下:
文章图片
image.png三、使用Postman测试接口时 1、POST请求 -> Body -> x-www-form-urlencoded
文章图片
image.png当切换为
x-www-form-urlencoded
时,Headers会自动添加Content-Type:application/x-www-form-urlencoded
文章图片
image.png当请求Send后,此时点
Code
,可以查看到和Chrome开发工具中(Request Headers处的Content-Type和Form Data)一样的数据文章图片
image.png2、POST请求 -> Body -> form-data
相当于html表单请求,value可为Text或文件。
文章图片
image.png可以不用手动指定编码格式,也可以指定编码为
multipart/form-data
文章图片
image.png划线处的分割线应该是被省略了。
文章图片
image.png可以更改左上角的类型,来查看相应的Headers代码,常见的是下面三种:
Java OK HTTP:
文章图片
image.pngJavaScript Jquery AJAX:
文章图片
JavaScript XHR:
文章图片
image.png总结【Post请求的两种编码格式(application/x-www-form-urlencoded和multipart/form-data)】POST请求的两种编码格式:
application/x-www-urlencoded
是浏览器默认的编码格式,用于键值对参数,参数之间用&
间隔;multipart/form-data
常用于文件等二进制,也可用于键值对参数,最后连接成一串字符传输(参考java OK HTTP)。除了这两个编码格式,还有application/json
也经常使用。接口代码
@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;
}
}
参考网址
HTML <
form>
标签的 enctype 属性:http://www.w3school.com.cn/tags/att_form_enctype.aspHttpUrlConnection 基础使用:https://www.cnblogs.com/libertycode/p/5979260.htmlSpringMvc接收multipart/form-data 传输的数据 及 PostMan各类数据类型的区别:https://www.cnblogs.com/ifindu-san/p/8251370.html#undefinedWhat is the boundary in multipart/form-data?:https://stackoverflow.com/questions/3508338/what-is-the-boundary-in-multipart-form-data
作者:DeppWang
链接:https://www.jianshu.com/p/53b5bd0f1d44
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
推荐阅读
- 记录vue项目 用hbuilder离线打包集成极光推送 安卓篇
- 安卓 版本判断 API
- Android Matrix
- 异常STATUS_FATAL_APP_EXIT(0x40000015)
- [原创] Delphi Create(Application) 和 Create(nil) 的区别
- Application.OpenURL()的妙用(unity打开网页,唤醒应用,打开文件夹)
- android如何让checkbox实现互斥以及android验证端cession登录注意事项
- AndroidGL ES-通过简单实例认识了解
- 从0系统学Android--3.6 RecyclerView