使用Spring WebClient以InputStream上传文件遇500内部服务器错误
问题场景
我在基于WebFlux的SpringBoot应用中开发了一个接收FilePart作为输入的API。为了用Tika库做文件类型校验,我先把FilePart转换成了InputStream,但用WebClient将这个流上传到目标API时,收到了500内部服务器错误。如果跳过转流步骤,直接用FilePart上传,WebClient就能正常工作。
出错代码
MultipartBodyBuilder builder = new MultipartBodyBuilder(); builder.part("file", new InputStreamResource(inputStream)).header("Content-Disposition", "form-data; name=file; filename=\"test.txt\""); return webClient .post() .uri("https://example.com/file") .contentType(MediaType.MULTIPART_FORM_DATA) .body(BodyInserters.fromMultipartData(builder.build())) .retrieve() .bodyToMono(String.class);
正常工作的代码
return webClient.post() .uri("https://example.com/file") .contentType(MediaType.MULTIPART_FORM_DATA) .body(BodyInserters.fromMultipartData("file", filePart)) .retrieve() .bodyToMono(String.class);
问题原因
- InputStream只能读取一次:
InputStreamResource包装的流是一次性的,WebFlux在异步处理过程中可能会多次尝试读取流,导致流耗尽或关闭,目标服务器无法正确解析文件内容。 - 缺少必要元数据:直接使用
InputStreamResource时,没有提供文件的Content-Type和内容长度,目标服务器无法识别文件类型或校验文件完整性,从而抛出500错误。 - Header格式问题:手动设置
Content-Disposition时的引号转义有误,导致表单数据解析失败。
解决方案
将InputStream转换为可重复读取的ByteArrayResource,同时正确设置文件元数据:
// 先将FilePart内容读取到字节数组(用于Tika校验和后续上传) byte[] fileBytes = filePart.content() .map(DataBuffer::asByteBuffer) .map(ByteBuffer::array) .reduce(new byte[0], (a, b) -> { byte[] result = new byte[a.length + b.length]; System.arraycopy(a, 0, result, 0, a.length); System.arraycopy(b, 0, result, a.length, b.length); return result; }) .block(); // Tika校验文件类型 Tika tika = new Tika(); String detectedMediaType = tika.detect(fileBytes); // 构建Multipart请求 MultipartBodyBuilder builder = new MultipartBodyBuilder(); builder.part("file", new ByteArrayResource(fileBytes)) .header("Content-Disposition", String.format("form-data; name=\"file\"; filename=\"%s\"", filePart.filename())) .header("Content-Type", detectedMediaType); return webClient .post() .uri("https://example.com/file") .contentType(MediaType.MULTIPART_FORM_DATA) .body(BodyInserters.fromMultipartData(builder.build())) .retrieve() .bodyToMono(String.class);
关键改进点
- 用
ByteArrayResource替代InputStreamResource,支持重复读取流,适配WebFlux异步处理模型。 - 保留原
FilePart的文件名,通过Tika自动识别并设置正确的Content-Type。 - 修正
Content-Disposition头的引号格式,确保表单数据解析正确。
内容的提问来源于stack exchange,提问作者Prajwal Raju P
相关产品推荐
相关产品推荐

