HTTP POST 请求的两种编码格式:application/x-www-form-urlencoded 和 multipart/form-data

HTTP POST 请求的两种编码格式:application/x-www-form-urlencoded 和 multipart/form-data

在常见业务开发中,POST 请求常常在这些地方使用:前端表单提交时、调用接口代码时和使用 Postman 测试接口时。我们下面来一一了解:

一、前端表单提交时

application/x-www-form-urlencoded

表单代码:

First name:

Last name:

通过测试发现可以正常访问接口,在 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 请求时,服务器怎么知道每个参数的开始位置和结束位置呢?

First name:

Last name:

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

文件上传

上传文件也要指定编码格式为 multipart/form-data。

如果是 SpringMVC 项目,要服务器能接受 multipart/form-data 类型参数,还要在 spring 上下文配置以下内容,SpringBoot 项目则不需要。

我们可以通过 FormData 对象模拟表单提交,用原始的 XMLHttpRequest 来发送数据,让我们可以在 Chrome 开发工具中查看到具体格式:

First name:

Last name:


格式如下:

二、调用接口代码时

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 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 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 也经常使用。

延伸阅读

HTML

标签的 enctype 属性

HttpUrlConnection 基础使用

SpringMvc 接收 multipart/form-data 传输的数据 及 PostMan 各类数据类型的区别

What is the boundary in multipart/form-data?

相关文章

为什么越来越多人选择单身?研究揭示:背后的问题可能出在男人身上

365bet在线网址 08-23

南宁名望木门怎么样有谁说说看

office365怎么登陆 08-12

乐豆豆游戏app

365bet在线网址 07-18

毁于一旦的意思解释及典故(故事)

office365怎么登陆 09-01