亚洲精品亚洲人成在线观看麻豆,在线欧美视频一区,亚洲国产精品一区二区动图,色综合久久丁香婷婷

              當(dāng)前位置:首頁 > IT技術(shù) > Web編程 > 正文

              HttpClient使用管道流提交Multipart請求
              2021-09-24 14:43:37

              HttpClient 是JDK11提供的一個全新HTTP客戶端Api,超級好用。

              Multipart 請求

              HttpClient 并沒有提供 Multipart 請求體的構(gòu)建Api。但是可以使用apache的開源httpmime庫來進行構(gòu)建。

              <!-- https://mvnrepository.com/artifact/org.apache.httpcomponents/httpmime -->
              <dependency>
                  <groupId>org.apache.httpcomponents</groupId>
                  <artifactId>httpmime</artifactId>
                  <version>4.5.13</version>
              </dependency>
              

              構(gòu)建一個 MultipartBody

              // 構(gòu)建Multipart請求
              HttpEntity httpEntity = MultipartEntityBuilder.create()
              		// 表單數(shù)據(jù)
              		.addPart("name", new StringBody(UriUtils.encode("SpringBoot中文社區(qū)", StandardCharsets.UTF_8), ContentType.APPLICATION_FORM_URLENCODED))
              		// JSON數(shù)據(jù)
              		.addPart("info", new StringBody("{"site": "https://springboot.io", "now": 2021}", ContentType.APPLICATION_JSON))
              		// 文件數(shù)據(jù)
              		.addBinaryBody("file", file, ContentType.APPLICATION_OCTET_STREAM, "eclipse-jee-2019-12-R-win32-x86_64.zip")
              		.build();
              
              ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream((int) httpEntity.getContentLength());
              
              // 把body寫入到內(nèi)存
              httpEntity.writeTo(byteArrayOutputStream);
              

              Multipart 請求可以一次性post多個子body,通常用來上傳本地磁盤上的文件。所以這種請求體可能會異常龐大。甚至內(nèi)存不能完整的存入整個請求體。那么這個時候有2種辦法可以解決。

              1. 先把構(gòu)建好的Body數(shù)據(jù)寫入到磁盤,再通過IO磁盤數(shù)據(jù),提交給服務(wù)器
              2. 使用管道流,在讀取磁盤數(shù)據(jù)進行body構(gòu)建的時候,直接通過管道提交到遠程服務(wù)器

              管道流

              管道流,顧名思義,可以往一邊寫,從另一邊讀。

              // 創(chuàng)建讀取流
              PipedInputStream pipedInputStream = new PipedInputStream();
              // 創(chuàng)建寫入流
              PipedOutputStream pipedOutputStream = new PipedOutputStream();
              // 連接寫入和讀取流
              pipedInputStream.connect(pipedOutputStream);
              

              通過往pipedOutputStream寫入數(shù)據(jù),就可以在pipedInputStream 讀取。

              不能使用單線程既讀又寫,因為讀寫都是阻塞方法。任何一方阻塞住了了,另一方就會一直處于等待狀態(tài),導(dǎo)致死鎖

              完整Demo

              客戶端

              package io.springcloud.test;
              
              import java.io.IOException;
              import java.io.InputStream;
              import java.io.PipedInputStream;
              import java.io.PipedOutputStream;
              import java.net.URI;
              import java.net.http.HttpClient;
              import java.net.http.HttpRequest;
              import java.net.http.HttpRequest.BodyPublishers;
              import java.net.http.HttpResponse;
              import java.net.http.HttpResponse.BodyHandlers;
              import java.nio.charset.StandardCharsets;
              import java.nio.file.Files;
              import java.nio.file.Paths;
              
              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.util.UriUtils;
              
              public class MainTest {
              
              
              	public static void main(String[] args) throws Exception {
              		
              		// 管道流
              		PipedInputStream pipedInputStream = new PipedInputStream();
              		PipedOutputStream pipedOutputStream = new PipedOutputStream();
              		pipedInputStream.connect(pipedOutputStream);
              		
              		// 本地文件
              		InputStream file =  Files.newInputStream(Paths.get("D:\eclipse-jee-2019-12-R-win32-x86_64.zip"));
              		
              		// 構(gòu)建Multipart請求
              		HttpEntity httpEntity = MultipartEntityBuilder.create()
              				// 表單數(shù)據(jù)
              				.addPart("name", new StringBody(UriUtils.encode("SpringBoot中文社區(qū)", StandardCharsets.UTF_8), ContentType.APPLICATION_FORM_URLENCODED))
              				// JSON數(shù)據(jù)
              				.addPart("info", new StringBody("{"site": "https://springboot.io", "now": 2021}", ContentType.APPLICATION_JSON))
              				// 文件數(shù)據(jù)
              				.addBinaryBody("file", file, ContentType.APPLICATION_OCTET_STREAM, "eclipse-jee-2019-12-R-win32-x86_64.zip")
              				.build();
              		
              		// 異步寫入數(shù)據(jù)到管道流
              		new Thread(() -> {
              			try (file; pipedOutputStream){
              				httpEntity.writeTo(pipedOutputStream);
              			} catch (IOException e) {
              				e.printStackTrace();
              			}
              		}).start();
              		
              		HttpClient httpClient = HttpClient.newHttpClient();
              		
              		try (pipedInputStream){
              			// 創(chuàng)建請求和請求體
              			HttpRequest request = HttpRequest
              						.newBuilder(new URI("http://localhost/upload"))
              						// 設(shè)置ContentType
              						.header("Content-Type", httpEntity.getContentType().getValue())
              						.header("Accept", "text/plain")   
              						// 從管道流讀取數(shù)據(jù),提交給服務(wù)器
              						.POST(BodyPublishers.ofInputStream(() -> pipedInputStream))
              						.build();
              			
              			// 執(zhí)行請求,獲取響應(yīng)
              			HttpResponse<String> responseBody = httpClient.send(request, BodyHandlers.ofString(StandardCharsets.UTF_8));
              			
              			System.out.println(responseBody.body());
              		}
              	}
              }
              

              服務(wù)端

              package io.springcloud.web.controller;
              
              import java.nio.charset.StandardCharsets;
              
              import org.slf4j.Logger;
              import org.slf4j.LoggerFactory;
              import org.springframework.http.ResponseEntity;
              import org.springframework.web.bind.annotation.PostMapping;
              import org.springframework.web.bind.annotation.RequestMapping;
              import org.springframework.web.bind.annotation.RequestPart;
              import org.springframework.web.bind.annotation.RestController;
              import org.springframework.web.multipart.MultipartFile;
              import org.springframework.web.util.UriUtils;
              
              import com.google.gson.JsonObject;
              
              
              @RestController
              @RequestMapping("/upload")
              public class UploadController {
              	
              	private static final Logger LOGGER = LoggerFactory.getLogger(UploadController.class);
              	
              	@PostMapping
              	public Object upload (@RequestPart("file") MultipartFile file,
              						@RequestPart("info") JsonObject info,
              						@RequestPart("name") String name) {
              		
              		LOGGER.info("file: name={}, size={}", file.getOriginalFilename(), file.getSize());
              		LOGGER.info("info: {}", info.toString());
              		LOGGER.info("name: {}", UriUtils.decode(name, StandardCharsets.UTF_8));
              		
              		return ResponseEntity.ok("success");
              	}
              }
              

              啟動服務(wù)端后,執(zhí)行客戶端請求,服務(wù)端日志輸出

              2021-09-24 13:38:15.067  INFO 2660 --- [  XNIO-1 task-1] i.s.web.controller.UploadController      : file: name=eclipse-jee-2019-12-R-win32-x86_64.zip, size=369653147
              2021-09-24 13:38:15.067  INFO 2660 --- [  XNIO-1 task-1] i.s.web.controller.UploadController      : info: {"site":"https://springboot.io","now":2021}
              2021-09-24 13:38:15.067  INFO 2660 --- [  XNIO-1 task-1] i.s.web.controller.UploadController      : name: SpringBoot中文社區(qū)
              

              首發(fā):https://springboot.io/t/topic/4185

              本文摘自 :https://www.cnblogs.com/

              開通會員,享受整站包年服務(wù)立即開通 >