使用DataBufferUtils写入响应时遇MessageBodyReader缺失问题求助
解决"Unable to find a MessageBodyReader"错误:二进制文件下载的正确姿势
问题根源
你的代码核心问题是混用了JAX-RS(Resteasy)客户端和Spring WebFlux的DataBufferUtils,且Resteasy的Rx调用逻辑错误地将二进制zip响应关联到了SSE(Server-Sent Events)处理流程:
- 调用
rx(FluxRxInvoker.class).get(DataBuffer.class)时,Resteasy的FluxRxInvoker默认会将请求关联到SSE事件流的处理,导致它尝试将application/zip类型的响应解析为SseEventInputImpl类型,但不存在对应的MessageBodyReader,因此抛出错误。 - 你后续尝试的自定义
MessageBodyReader方向完全错误:JAXB是用来解析XML的,而你下载的是二进制zip文件,用XML解析二进制流必然会出现"Content is not allowed in prolog"的XML解析错误。
正确解决方案
方案1:使用Spring WebFlux的WebClient(推荐)
既然你已经引入了spring-boot-starter-webflux,直接用WebClient来处理HTTP请求,它和DataBufferUtils天然适配,无需依赖Resteasy的JAX-RS客户端:
import org.springframework.core.io.buffer.DataBufferUtils; import org.springframework.web.reactive.function.client.WebClient; import java.nio.file.Path; import java.nio.file.Paths; import java.nio.file.StandardOpenOption; public class Downloader { public static void main(String[] args) { WebClient webClient = WebClient.create(); Path path = Paths.get("sample.zip"); webClient.get() .uri("https://www.learningcontainer.com/wp-content/uploads/2020/05/sample-zip-file.zip") .retrieve() .bodyToFlux(org.springframework.core.io.buffer.DataBuffer.class) .doOnNext(dataBuffer -> DataBufferUtils.release(dataBuffer)) .as(dataBufferFlux -> DataBufferUtils.write(dataBufferFlux, path, StandardOpenOption.CREATE)) .block(); } }
方案2:如果坚持使用Resteasy客户端
需要正确获取二进制输入流,再转换为Spring DataBuffer供DataBufferUtils写入,避免触发SSE处理逻辑:
import org.jboss.resteasy.client.jaxrs.ResteasyClient; import org.jboss.resteasy.client.jaxrs.ResteasyClientBuilder; import org.springframework.core.io.buffer.DataBuffer; import org.springframework.core.io.buffer.DefaultDataBufferFactory; import reactor.core.publisher.Flux; import java.io.InputStream; import java.nio.file.Path; import java.nio.file.Paths; import java.nio.file.StandardOpenOption; public class Downloader { public static void main(String[] args) { ResteasyClient client = new ResteasyClientBuilder().build(); try (InputStream inputStream = client.target("https://www.learningcontainer.com/wp-content/uploads/2020/05/sample-zip-file.zip") .request() .get(InputStream.class)) { DefaultDataBufferFactory bufferFactory = new DefaultDataBufferFactory(); Flux<DataBuffer> dataBufferFlux = Flux.generate(sink -> { byte[] buffer = new byte[4096]; int bytesRead; try { if ((bytesRead = inputStream.read(buffer)) != -1) { sink.next(bufferFactory.wrap(buffer, 0, bytesRead)); } else { sink.complete(); } } catch (Exception e) { sink.error(e); } }); Path path = Paths.get("sample.zip"); org.springframework.core.io.buffer.DataBufferUtils.write(dataBufferFlux, path, StandardOpenOption.CREATE).block(); } catch (Exception e) { e.printStackTrace(); } finally { client.close(); } } }
额外注意事项
- 依赖清理:如果使用方案1,可以移除Resteasy相关的依赖(
jboss-jaxrs-api_2.1_spec、resteasy-reactor、resteasy-jackson2-provider),避免依赖冲突。 - 文件命名:你之前将zip文件保存为
file.txt,建议改为sample.zip,避免文件格式识别问题。
内容的提问来源于stack exchange,提问作者Sunny
相关产品推荐
相关产品推荐

