multipart/form-data
,多部件请求体。这个请求体比较特殊,它可以拆分为多个部件,每个部件都有自己的header
和body
,最常用的地方就是:客户端文件上传,因为有多个部件,在上传文件的时候,还可以在body
中添加其他的数据。json
,form
。。。
一般来说,都是客户端发起multipart/form-data
请求 ,服务器进行解析。而且这种东西的编码解码工作一般都是由底层的容器/框架完成。开发根本不必关心。但是我最近遇到了一个需求:
服务器响应
multipart/form-data
(包含了一个二进制文件和其他的文本数据),客户端来解析
意味着,需要自己完成2个东西
- 在服务端完成
multipart/form-data
的数据编码,并且响应给客户端 - 在客户端获取到响应后,进行数据的解码
multipart/form-data
的请求体,看起来像这样(省略了部分 header)
POST /foo HTTP/1.1
Content-Length: 68137
Content-Type: multipart/form-data; boundary=---------------------------974767299852498929531610575
---------------------------974767299852498929531610575
Content-Disposition: form-data; name="description"
some text
---------------------------974767299852498929531610575
Content-Disposition: form-data; name="myFile"; filename="foo.txt"
Content-Type: text/plain
(content of the uploaded file foo.txt)
---------------------------974767299852498929531610575
服务端的编码
使用 org.apache.httpcomponents
库进行编码
<!-- https://mvnrepository.com/artifact/org.apache.httpcomponents/httpmime -->
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpmime</artifactId>
<version>4.5.12</version>
</dependency>
Controller
通过 MultipartEntityBuilder
, 添加多个部件,每个部件有自己的名字,类型。构建出一个 HttpEntity
对象。可以从这个对象中获取到编码后的IO流以及ContentType
,直接响应给 客户端就完事儿,比较简单。
import java.io.File;
import java.nio.charset.StandardCharsets;
import javax.servlet.http.HttpServletResponse;
import org.apache.http.HttpEntity;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.entity.mime.content.StringBody;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.util.UriUtils;
@RestController
@RequestMapping("/test")
public class TestController {
@GetMapping
public void test (HttpServletResponse response) throws Exception {
HttpEntity httpEntity = MultipartEntityBuilder.create(