Issue
I want to send a request of a file through WebClient
by POST method, and I need to send the file as byte[]
to get right response.
I made MultipartFile file
to byte[]
, and then I thought I need to use BodyInserters
to make this body contains byte[]
but I don't know how to make that request body.
How to send a POST request that contains byte array by WebClient
?
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.reactive.function.BodyInserters;
import org.springframework.web.reactive.function.client.WebClient;
@RestController
public class ApiController {
@PostMapping(value = "/update")
public String update(@RequestParam("file") MultipartFile file, @RequestParam("uri") String uri ) {
String result = "{error : error}";
byte[] byteArr;
BodyInserters byteArrInserter;
try {
byteArr = file.getBytes();
A? publisher = B?.C?; // I don't know what will be right for those A?, B?, C?
byteArrInserter = BodyInserters.fromDataBuffers(publisher); // In fact, I'm not sure this method will be good for this situation, either.
} catch (Exception e) {
System.out.println(e);
}
WebClient client = WebClient.builder()
.codecs(configurer -> configurer.defaultCodecs().maxInMemorySize( 1024*1024*1024 * 2)) // 2GB
.build();
try {
result = client
.post()
.uri(uri)
.body(byteArrInserter)
.retrieve().bodyToMono(String.class).block();
} catch (Exception e) {
System.out.println(e);
}
return result;
}
}
Solution
I don't know how to send binary content with WebClient, but there are some other options. First there is SpringBoot own RestTemplate class which is an alternative to WebClient. Here is an comparative article about them both: Spring WebClient vs. RestTemplate. If you wish to use third party Http clients that definitely can send binary content you can look at 2 popular choices:
And finally, I wrote my own Http client that is part of Open-source MgntUtils library written and maintained by me. This Http client is very simplistic but does the job. I am actually at the process of adding the feature that allows to upload binary info. I haven't published it yet, but you can download the branch or look at the code how I do it there. The branch is located here The HttpClient class is here. See method public String sendHttpRequest(String requestUrl, HttpMethod callMethod, ByteBuffer data) throws IOException
at line 162. The method with which I tested this method looks like this:
private static void testHttpClientBinaryUpload() {
try {
byte[] content = Files.readAllBytes(Paths.get("C:\\Michael\\Personal\\pics\\testPic.jpg"));
HttpClient client = new HttpClient();
Integer length = content.length;
Files.write(Paths.get("C:\\Michael\\tmp\\testPicOrig.jpg"), content);
client.setRequestHeader("Content-Length", length.toString());
String result = client.sendHttpRequest("http://localhost:8080/upload", HttpMethod.POST, ByteBuffer.wrap(content));
System.out.println(result);
System.out.println("HTTP " + client.getLastResponseCode() + " " + client.getLastResponseMessage());
} catch (Exception e) {
System.out.println(TextUtils.getStacktrace(e, "com.mgnt."));
}
}
And server side Springboot rest controller that receives the request looks like this:
@RestController
@RequestMapping("/upload")
public class UploadTestController {
@PostMapping
public ResponseEntity<String> uploadTest(HttpServletRequest request) {
try {
String lengthStr = request.getHeader("content-length");
int length = TextUtils.parseStringToInt(lengthStr, -1);
if(length > 0) {
byte[] buff = new byte[length];
ServletInputStream sis =request.getInputStream();
int counter = 0;
while(counter < length) {
int chunkLength = sis.available();
byte[] chunk = new byte[chunkLength];
sis.read(chunk);
for(int i = counter, j= 0; i < counter + chunkLength; i++, j++) {
buff[i] = chunk[j];
}
counter += chunkLength;
if(counter < length) {
TimeUtils.sleepFor(5, TimeUnit.MILLISECONDS);
}
}
Files.write(Paths.get("C:\\Michael\\tmp\\testPic.jpg"), buff);
}
} catch (Exception e) {
System.out.println(TextUtils.getStacktrace(e));
}
return ResponseEntity.ok("Success");
}
}
I am planning to publish the new version of the library in few days and this feature will be included. In any case here is the link to Maven Artifacts, Github and Javadoc
Answered By - Michael Gantman
Answer Checked By - Mary Flores (JavaFixing Volunteer)