网关微服务转发Multipart文件失败 下游接收file参数为null
问题根因
- 网关转发时构造的请求不符合
multipart/form-data文件上传协议规范,下游Spring MVC无法解析出名为file的MultipartFile参数,最终拿到null。 - 原有实现直接将文件字节数组塞入
HttpEntity发送,默认请求头Content-Type为application/octet-stream,既没有指定表单字段名,也没有multipart请求要求的boundary分隔符、文件元数据(文件名等),完全不符合文件上传接口的请求格式要求。 - 直连下游服务正常,是因为调用方直接发送了标准multipart格式请求,Spring可以正常解析参数。
修复方案
替换网关层try代码块内的请求构造逻辑,构造标准的multipart表单请求转发即可,代码如下:
try { // 构造multipart表单请求体 MultiValueMap<String, Object> formBody = new LinkedMultiValueMap<>(); // 将文件包装为字节数组资源,指定表单字段名与下游接口参数名一致为file formBody.add("file", new ByteArrayResource(file.getBytes()){ // 必须重写getFilename返回文件名,否则下游无法识别为文件字段 @Override public String getFilename() { return file.getOriginalFilename(); } }); // 构造请求头,指定Content-Type为multipart/form-data HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.MULTIPART_FORM_DATA); // 组装请求实体并转发 HttpEntity<MultiValueMap<String, Object>> forwardRequest = new HttpEntity<>(formBody, headers); ResponseEntity<DocumentResponseDTO> entity = restTemplate.postForEntity(uriStatementUpload.toUri(), forwardRequest, DocumentResponseDTO.class); return entity; } catch (HttpClientErrorException e) { return ResponseEntity.status(e.getStatusCode()).body(e.getResponseBodyAsString()); } catch (IOException e) { return ResponseEntity.status(500).body("IOException while getting bytes stream from file"); }
注意事项
- 不要直接传入裸byte数组作为请求体,必须使用
LinkedMultiValueMap作为multipart表单的载体,这是Spring RestTemplate处理文件上传的标准数据结构 - 包装文件资源时必须重写
getFilename()方法返回原始文件名,否则Spring构造请求时不会为该字段生成filename属性,下游依然会解析失败 - 表单字段的key必须为
file,和下游接口的形参名完全匹配,否则参数绑定会失败 - 不需要手动设置multipart请求的boundary参数,RestTemplate会在发送请求时自动生成合法的分隔符
内容的提问来源于stack exchange,提问作者Eljah
相关产品推荐
相关产品推荐

