咸鱼

咸鱼是以盐腌渍后,晒干的鱼

0%

深入解析HTTP--Multipart

描述

multipart/form-data 用以向服务器发送二进制数据,一般用于多个文件和参数一起发送。

服务端接收数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
@RequestMapping("/test/multipart")
@ResponseBody
public String handleFileUpload(@RequestPart("file")MultipartFile file,
@RequestPart("describe")String describe){

System.out.println("describe="+describe);
if(!file.isEmpty()){

try {
BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(new File(file.getOriginalFilename())));
out.write(file.getBytes());
out.flush();
out.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
return e.getMessage();

} catch (IOException e) {
e.printStackTrace();
return e.getMessage();
}
return"OK";
}else{
return"file is null";
}
}

客户端

  1. 每一个文件或者参数做为一个Part
  2. Part 都包含头信息部分
  3. Part 头信息中必须包含一个 Content-Disposition 头,其他的头信息则为可选项, 比如 Content-Type
  4. 每个 Part 使用 --boundary 分割,最后一行使用 --boundary-- 结尾

举例:

发送一个请求,为了方便,这里上传一个txt文件 hello.txt 和一个参数 describe,二进制文件比如图片,直接发它的byte就可以了。

postman发送如图:
postman_multipart.png

postman请求发送的数据(每一行结尾都有一个 CRLF,空行也是有 CRLF):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
POST /test/multipart HTTP/1.1
cache-control: no-cache
Postman-Token: 8adf3cf7-6779-4273-ba5a-8b8a42103a02
User-Agent: PostmanRuntime/7.4.0
Accept: */*
Host: 127.0.0.1:7878
accept-encoding: gzip, deflate
content-type: multipart/form-data; boundary=--------------------------443008154012991210048296
content-length: 331
Connection: keep-alive

----------------------------443008154012991210048296
Content-Disposition: form-data; name="file"; filename="hello.txt"
Content-Type: text/plain

12345
----------------------------443008154012991210048296
Content-Disposition: form-data; name="describe"

this is text
----------------------------443008154012991210048296--
HTTP/1.1 200
Content-Type: text/plain;charset=UTF-8
Content-Length: 2
Date: Sat, 22 Dec 2018 09:38:14 GMT

OK

原始数据:

1
2
3
504f5354202f746573742f6d756c74697061727420485454502f312e310d0a63616368652d636f6e74726f6c3a206e6f2d63616368650d0a506f73746d616e2d546f6b656e3a2038616466336366372d363737392d343237332d626135612d3862386134323130336130320d0a557365722d4167656e743a20506f73746d616e52756e74696d652f372e342e300d0a4163636570743a202a2f2a0d0a486f73743a203132302e37392e34332e34343a373837380d0a6163636570742d656e636f64696e673a20677a69702c206465666c6174650d0a636f6e74656e742d747970653a206d756c7469706172742f666f726d2d646174613b20626f756e646172793d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d3434333030383135343031323939313231303034383239360d0a636f6e74656e742d6c656e6774683a203333310d0a436f6e6e656374696f6e3a206b6565702d616c6976650d0a0d0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d3434333030383135343031323939313231303034383239360d0a436f6e74656e742d446973706f736974696f6e3a20666f726d2d646174613b206e616d653d2266696c65223b2066696c656e616d653d2268656c6c6f2e747874220d0a436f6e74656e742d547970653a20746578742f706c61696e0d0a0d0a
31323334350d0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d3434333030383135343031323939313231303034383239360d0a436f6e74656e742d446973706f736974696f6e3a20666f726d2d646174613b206e616d653d226465736372696265220d0a0d0a7468697320697320746578740d0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d3434333030383135343031323939313231303034383239362d2d0d0a
485454502f312e3120323030200d0a436f6e74656e742d547970653a20746578742f706c61696e3b636861727365743d5554462d380d0a436f6e74656e742d4c656e6774683a20320d0a446174653a205361742c2032322044656320323031382030393a33383a313420474d540d0a0d0a4f4b

值得注意的一个地方就是 boundary ,postman和大多数浏览器都是用 --------- 开头作为boundary 的值,而我们参照它来拼包时,很容易忘记分隔符是 -- + boundary

比如上面 postman 定义了 boundary 的值为

--------------------------443008154012991210048296 (26个 - ),

而分割符的值是

----------------------------443008154012991210048296 (28个 - )。

但其实只有保证整个包内出现和 boundary 相同的内容即可,我们重新定义一个没有 - 的值:

1
2
3
4
5
6
...
content-type: multipart/form-data; boundary=fe1f62da7dbc44bea38db39dbf07413b

--fe1f62da7dbc44bea38db39dbf07413b
Content-Disposition: form-data; name="file"; filename="hello.txt"
...

这样就可以了。