Post请求的两种编码格式:application/x-www-form-urlencoded和multipart/fo

时间:2021-09-13 06:28:48

在常见业务开发中,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

  Post请求的两种编码格式:application/x-www-form-urlencoded和multipart/fo 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="Mickey&"><br> Last name: <input type="text" name="lastName" value="Mouse "><br> <input type="submit" value="提交"> </form> 

我们在开发者工具中可以看出multipart/form-data不会对参数编码,使用的boundary(分割线),相当于&boundary的值是----Web**AJv3

  Post请求的两种编码格式:application/x-www-form-urlencoded和multipart/fo 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="提交"> </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> 

格式如下:

  Post请求的两种编码格式:application/x-www-form-urlencoded和multipart/fo 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 = 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&&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   "rn"); dataOutputStream.writeBytes("Content-Disposition: form-data; name=""   encode(key)   ""rn"); dataOutputStream.writeBytes("rn"); dataOutputStream.writeBytes(encode(value)   "rn"); } //最后一个分隔符的结尾后面要跟"--" 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