描述
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"; } }
|
客户端
- 每一个文件或者参数做为一个Part
- Part 都包含头信息部分
- Part 头信息中必须包含一个
Content-Disposition
头,其他的头信息则为可选项, 比如 Content-Type
等
- 每个 Part 使用
--boundary
分割,最后一行使用 --boundary--
结尾
举例:
发送一个请求,为了方便,这里上传一个txt文件 hello.txt 和一个参数 describe,二进制文件比如图片,直接发它的byte就可以了。
postman发送如图:
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
Content-Disposition: form-data; name="file"; filename="hello.txt" Content-Type: text/plain
12345
Content-Disposition: form-data; name="describe"
this is text
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" ...
|
这样就可以了。