使用Java HttpURLConnection发送二进制内容到SpringBoot服务报错如何解决
问题原因
- 服务端配置冲突:接口要求请求Content-Type为
multipart/form-data,但使用@RequestBody注解默认只能处理application/json等非multipart类型的请求体,Spring找不到对应转换器解析请求。 - 客户端请求格式错误:虽然设置了
multipart/form-data的请求头,但实际发送的是普通JSON字符串,且没有携带multipart协议要求的边界(boundary)分隔符,服务端无法识别请求格式,默认将请求识别为text/plain;charset=UTF-8,和接口要求的类型不匹配,因此抛出异常。 - 字节数组传输逻辑错误:使用
Arrays.toString(bytes)将二进制数组转为字符串格式存入JSON,会导致二进制内容失真,体积膨胀,无法正确还原原始文件内容。
修复方案
根据业务场景可以选择以下两种方案之一:
方案1:走multipart/form-data协议传输二进制(推荐用于文件上传,效率更高)
服务端修改
// 移除硬编码的content-type要求,改用consumes声明,接收参数换成MultipartFile @RequestMapping(value = "/bytelink", method = RequestMethod.POST, consumes = "multipart/form-data") ResponseEntity<String> postBytes(@ApiParam(value = "Upload bytes") @RequestParam("file") MultipartFile file) throws IOException { return ResponseEntity.ok(byteLinkService.postBytes(file.getBytes())); }
客户端修改
//byte[] bytes 是待上传的文件内容 String boundary = "----Boundary" + Long.toHexString(System.currentTimeMillis()); URL url = new URL(this.endpoint + "/bytelink/"); HttpURLConnection con = (HttpURLConnection) url.openConnection(); con.setRequestMethod("POST"); con.setRequestProperty("Authorization", "Bearer " + token); // 请求头携带边界参数 con.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + boundary); con.setRequestProperty("Accept", "*/*"); con.setDoOutput(true); try (OutputStream os = con.getOutputStream()) { // 写入multipart起始分隔符 os.write(("--" + boundary + "\r\n").getBytes()); // 写入文件字段头信息 os.write(("Content-Disposition: form-data; name=\"file\"; filename=\"upload.bin\"\r\n").getBytes()); os.write(("Content-Type: application/octet-stream\r\n\r\n").getBytes()); // 直接写入原始二进制内容 os.write(bytes); // 写入multipart结束分隔符 os.write(("\r\n--" + boundary + "--\r\n").getBytes()); os.flush(); } int status = con.getResponseCode(); System.out.println(status);
方案2:走application/json协议传输(适合小体积字节数组)
服务端修改
// 把接收类型改成application/json,保留@RequestBody接收自定义Bytes对象即可 @RequestMapping(value = "/bytelink", method = RequestMethod.POST, consumes = "application/json") ResponseEntity<String> postBytes(@ApiParam(value = "Upload bytes.", example = "0") @RequestBody Bytes bytes) { return ResponseEntity.ok(byteLinkService.postBytes(bytes.getBytes())); }
客户端修改
import java.util.Base64; import java.nio.charset.StandardCharsets; //byte[] bytes 是待上传的文件内容 URL url = new URL(this.endpoint + "/bytelink/"); HttpURLConnection con = (HttpURLConnection) url.openConnection(); con.setRequestMethod("POST"); con.setRequestProperty("Authorization", "Bearer " + token); // 改成json格式请求头 con.setRequestProperty("Content-Type", "application/json; charset=utf-8"); con.setRequestProperty("Accept", "*/*"); con.setDoOutput(true); // 字节数组转Base64编码,避免二进制内容在JSON中转义出错 String base64Bytes = Base64.getEncoder().encodeToString(bytes); String jsonInputString = "{\"bytes\": \"" + base64Bytes + "\"}"; try (OutputStream os = con.getOutputStream()) { byte[] input = jsonInputString.getBytes(StandardCharsets.UTF_8); os.write(input, 0, input.length); } int status = con.getResponseCode(); System.out.println(status);
内容的提问来源于stack exchange,提问作者k-wasilewski
相关产品推荐
相关产品推荐

