Spring WebFlux中HttpMessageConverter的等价组件是什么?——MVC迁移WebFlux遇406错误问询
在Spring WebFlux的响应式模型里,替代Spring MVC中HttpMessageConverter的是**HttpMessageReader和HttpMessageWriter**这一对组件。和MVC里既负责请求读取又负责响应写入的HttpMessageConverter不同,WebFlux把这两个职责拆分成了独立的接口:HttpMessageReader专门处理请求体的解析,HttpMessageWriter负责响应体的序列化,完美适配异步非阻塞的编程模型。
你遇到的HTTP 406错误,本质是WebFlux默认的消息读写器列表里没有你之前自定义的、针对text/plain和text/csv的错误对象转换逻辑,导致框架找不到合适的转换器来处理响应,因此返回了"Not Acceptable"的状态码。
下面针对你的场景(错误对象转文本/CSV格式),给出具体的实现和配置方案:
1. 自定义HttpMessageWriter处理响应转换
因为你需要的是把错误对象转换成text/plain或text/csv格式的响应,所以重点实现HttpMessageWriter接口即可:
第一步:实现自定义Writer
import org.springframework.core.ResolvableType; import org.springframework.http.MediaType; import org.springframework.http.server.reactive.ServerHttpRequest; import org.springframework.http.server.reactive.ServerHttpResponse; import reactor.core.publisher.Mono; import java.util.List; public class ErrorObjectHttpMessageWriter implements HttpMessageWriter<YourErrorObject> { @Override public boolean canWrite(ResolvableType elementType, MediaType mediaType) { // 校验是否是目标错误对象类型,且支持指定的媒体类型 return YourErrorObject.class.isAssignableFrom(elementType.resolve()) && (MediaType.TEXT_PLAIN.isCompatibleWith(mediaType) || MediaType.parseMediaType("text/csv").isCompatibleWith(mediaType)); } @Override public Mono<Void> write(Publisher<? extends YourErrorObject> inputStream, ResolvableType elementType, MediaType mediaType, ServerHttpRequest request, ServerHttpResponse response) { // 处理错误对象到文本/CSV的转换逻辑 return inputStream.next() .map(errorObj -> { if (MediaType.TEXT_PLAIN.isCompatibleWith(mediaType)) { return errorObj.toPlainText(); // 假设你的错误对象有生成纯文本的方法 } else { return errorObj.toCsvString(); // 生成CSV格式字符串的方法 } }) .flatMap(formattedText -> { response.getHeaders().setContentType(mediaType); return response.writeWith(Mono.just(response.bufferFactory().wrap(formattedText.getBytes()))); }); } @Override public List<MediaType> getWritableMediaTypes() { // 声明该Writer支持的媒体类型 return List.of(MediaType.TEXT_PLAIN, MediaType.parseMediaType("text/csv")); } }
第二步:注册到WebFlux配置
通过WebFluxConfigurer把自定义Writer加入到框架的codec列表中:
import org.springframework.context.annotation.Configuration; import org.springframework.http.codec.ServerCodecConfigurer; import org.springframework.web.reactive.config.WebFluxConfigurer; @Configuration public class WebFluxCustomCodecConfig implements WebFluxConfigurer { @Override public void configureHttpMessageCodecs(ServerCodecConfigurer configurer) { // 注册自定义的错误对象Writer configurer.customCodecs().register(new ErrorObjectHttpMessageWriter()); // 如果需要让自定义Writer优先被选中,可以调整顺序 // configurer.customCodecs().order(0); } }
2. 结合全局异常处理直接指定响应格式
如果你的错误对象是在全局异常处理器中返回的,也可以直接在异常处理方法里手动指定媒体类型和转换逻辑,不需要单独实现Writer:
import org.springframework.http.MediaType; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.RestControllerAdvice; import org.springframework.web.reactive.function.server.ServerResponse; import reactor.core.publisher.Mono; @RestControllerAdvice public class GlobalErrorHandler { @ExceptionHandler(YourBusinessException.class) public Mono<ServerResponse> handleBusinessException(YourBusinessException ex) { YourErrorObject errorObj = new YourErrorObject(ex.getErrorCode(), ex.getMessage()); // 根据请求的Accept头动态返回格式,或者手动指定 return ServerResponse.status(ex.getHttpStatus()) .contentType(MediaType.TEXT_PLAIN) // 换成text/csv即可返回CSV格式 .bodyValue(errorObj.toPlainText()); } }
补充说明
和MVC的HttpMessageConverter相比,WebFlux的HttpMessageReader/HttpMessageWriter是完全基于响应式流设计的,所有处理逻辑都返回Mono或Flux,适配异步非阻塞的场景。如果你的原有转换器同时处理请求和响应,那需要分别实现HttpMessageReader和HttpMessageWriter;但针对你的场景,只需要处理响应转换,所以HttpMessageWriter就足够了。
内容的提问来源于stack exchange,提问作者Nicklas2751

