当前位置: 首页 > 后端技术 > Java

HttpClient使用管道流提交Multipart请求

时间:2023-04-01 14:17:12 Java

HttpClient是JDK11提供的一个新的HTTP客户端API,超级好用。Multipart请求HttpClient没有提供Multipart请求体的构造API。但它可以使用Apache的开源httpmime库构建。org.apache.httpcomponentshttpmime4.5.13BuildaMultipartBody//构建Multipart请求HttpEntityhttpEntity=MultipartEntityBuilder.create()//Formdata.addPart("name",newStringBody(UriUtils.encode("SpringBoot中文社区",StandardCharsets.UTF_8),ContentType.APPLICATION_FORM_URLENCODED))//JSONdata.addPart("info",newStringBody("{\"site\":\"https://springboot.io\",\"now\":2021}",ContentType.APPLICATION_JSON))//文件data.addBinaryBody("文件",文件,ContentType.APPLICATION_OCTET_STREAM,"eclipse-jee-2019-12-R-win32-x86_64.zip").build();ByteArrayOutputStreambyteArrayOutputStream=newByteArrayOutputStream((int)httpEntity.getContentLength());//将正文写入内存httpEntity.writeTo(byteArrayOutp流);multipart请求可以一次发布多个子body,通常用于上传本地磁盘文件,所以这种请求body可能会非常大。即使是内存也不能完全存储在整个请求体中。那么这次有2种方法可以解决。先将建好的body数据写入磁盘,然后将IO磁盘数据提交给服务器使用pipeline流。读取磁盘数据进行body构建时,直接通过pipeline管道流pipelineflow提交给远程服务器。顾名思义,您可以在一侧写入并从另一侧读取。//创建一个读流PipedInputStreampipedInputStream=newPipedInputStream();//创建一个写流PipedOutputStreampipedOutputStream=newPipedOutputStream();//连接写流和读流pipedInputStream.connect(pipedOutputStream);通过向pipedOutputStream写入数据,它可以在pipedInputStream中读取。不能用单线程读写,因为读写都是阻塞方式。如果任何一方被阻塞,另一方将一直处于等待状态,导致死锁completeDemoclientpackageio.springcloud.test;importjava.io.IOException;importjava.io.InputStream;importjava.io.PipedInputStream;导入java.io.PipedOutputStream;导入java.net.URI;导入java.net.http.HttpClient;导入java.net.http.HttpRequest;导入java.net.http.HttpRequest.BodyPublishers;导入java.net。http.HttpResponse;导入java.net.http.HttpResponse.BodyHandlers;导入java.nio.charset.StandardCharsets;导入java.nio.file.Files;导入java.nio.file.Paths;导入org.apache.http.HttpEntity;导入org.apache.http.entity.ContentType;导入org.apache.http.entity.mime.MultipartEntityBuilder;导入org.apache.http.entity.mime.content.StringBody;导入org.springframework.web.util.UriUtils;publicclassMainTest{publicstaticvoidmain(String[]args)throwsException{//管道流PipedInputStreampipedInputStream=newPipedInputStream();PipedOutputStreampipedOutputStream=newPipedOutput溪流();pipedInputStream.connect(pipedOutputStream);//本地文件InputStreamfile=Files.newInputStream(Paths.get("D:\\eclipse-jee-2019-12-R-win32-x86_64.zip"));//构建一个Multipart请求HttpEntity=MultipartEntityBuilder.create()//FormData.addPart("name",newStringBody(UriUtils.encode("SpringBootChineseCommunity",StandardCharsets.UTF_8),ContentType.APPLICATION_FORM_URLENCODED))//JSONData.addPart("info",newStringBody("{\"site\":\"https://springboot.io\",\"now\":2021}",ContentType.APPLICATION_JSON))//文件数据.addBinaryBody("文件",文件,ContentType.APPLICATION_OCTET_STREAM,"eclipse-jee-2019-12-R-win32-x86_64.zip").build();//异步写入数据到管道流newThread(()->{try(file;pipedOutputStream){httpEntity.writeTo(pipedOutputStream);}catch(IOExceptione){e.printStackTrace();}})。开始();HttpClienthttpClient=HttpClient.newHttpClient();try(pipedInputStream){//创建请求和请求体HttpRequestrequest=HttpRequest.newBuilder(newURI("http://localhost/upload"))//设置ContentType.header("Content-Type",httpEntity.getContentType(.getValue()).header("Accept","text/plain")//从Pipeline流中读取数据并提交给服务器.POST(BodyPublishers.ofInputStream(()->pipedInputStream)).build();//执行请求并获取响应HttpResponseresponseBody=httpClient.send(request,BodyHandlers.ofString(StandardCharsets.UTF_8));System.out.println(responseBody.body());}}}服务器包io.springcloud.web.controller;i导入java.nio.charset.StandardCharsets;导入org.slf4j.Logger;导入org.slf4j.LoggerFactory;导入org.springframework.http.ResponseEntity;导入org.springframework.web.bind.annotation.PostMapping;导入org.springframework。web.bind.annotation.RequestMapping;导入org.springframework.web.bind.annotation.RequestPart;导入org.springframework.web.bind.annotation.RestController;导入org.springframework.web.multipart.MultipartFile;导入org.springframework。web.util.UriUtils;importcom.google.gson.JsonObject;@RestController@RequestMapping("/upload")publicclassUploadController{privatestaticfinalLoggerLOGGER=LoggerFactory.getLogger(UploadController.class);@PostMappingpublicObjectupload(@RequestPart("file")MultipartFilefile,@RequestPart("info")JsonObjectinfo,@RequestPart("name")Stringname){LOGGER.info("file:name={},size={}",file.getOriginalF文件名(),文件.getSize());LOGGER.info("信息:{}",info.toString());LOGGER.info("name:{}",UriUtils.decode(name,StandardCharsets.UTF_8));返回ResponseEntity.ok("成功");}}启动服务器后,执行客户端请求,服务器日志输出2021-09-2413:38:15.067INFO2660---[XNIO-1task-1]i.s.web.controller.UploadController:file:name=eclipse-jee-2019-12-R-win32-x86_64.zip,size=3696531472021-09-2413:38:15.067INFO2660---[XNIO-1task-1]i.s.web.controller.UploadController:信息:{"site":"https://springboot.io","now":2021}2021-09-2413:38:15.067INFO2660---[XNIO-1task-1]i.s.web.controller.UploadController:名称:SpringBoot中文社区首发:https://springboot.io/t/topic...