Spring WebFlux自定义WebExceptionHandler无法写入HTTP响应体问题
Spring WebFlux自定义WebExceptionHandler响应内容为空的解决方案
我来帮你解决这个问题!你遇到的响应状态码正确但内容长度为0的情况,核心问题出在WebFlux异步响应的处理顺序上。
问题原因分析
你当前的代码中,先调用了exchange.getResponse().writeWith(Mono.just(db)),紧接着直接调用return exchange.getResponse().setComplete()。但WebFlux的所有IO操作都是异步非阻塞的,writeWith返回的Mono还没完成(数据还没写入响应),setComplete就已经标记响应完成了,导致响应被提前关闭,序列化后的错误数据根本没来得及发送给客户端。
修复方案
你需要把写数据和标记响应完成的操作通过异步链式调用绑定,确保写操作完成后再结束响应。修改你的代码片段如下:
WebExchangeBindException cvex = (WebExchangeBindException) ex; Map<String, String> errors = new HashMap<>(); log.debug("errors:" + cvex.getFieldErrors()); cvex.getFieldErrors().forEach(ev -> errors.put(ev.getField(), ev.getDefaultMessage())); log.debug("handled errors::" + errors); try { DataBuffer db = new DefaultDataBufferFactory().wrap(objectMapper.writeValueAsBytes(errors)); ServerHttpResponse response = exchange.getResponse(); response.setStatusCode(HttpStatus.UNPROCESSABLE_ENTITY); response.getHeaders().setContentType(MediaType.APPLICATION_JSON); // 替换弃用的APPLICATION_JSON_UTF8 // 链式调用,确保writeWith完成后再标记响应完成 return response.writeWith(Mono.just(db)) .then(response.setComplete()); } catch (JsonProcessingException e) { log.error("Failed to serialize error response", e); // 用日志替代printStackTrace return Mono.error(e); // 抛出异常让后续处理器处理 }
关键修改点:
- 将
writeWith和setComplete通过then链式调用,保证异步操作的顺序性 - 替换了已弃用的
MediaType.APPLICATION_JSON_UTF8为MediaType.APPLICATION_JSON(Spring 5.2+推荐) - 把
printStackTrace换成了日志记录,更符合生产环境规范 - 异常捕获后返回
Mono.error(e),而不是空的Mono.empty(),这样能让框架感知到错误并处理
额外优化建议
如果想让代码更简洁,也可以使用ServerResponse来构建响应,它会自动处理异步响应的生命周期:
WebExchangeBindException cvex = (WebExchangeBindException) ex; Map<String, String> errors = new HashMap<>(); cvex.getFieldErrors().forEach(ev -> errors.put(ev.getField(), ev.getDefaultMessage())); return ServerResponse.status(HttpStatus.UNPROCESSABLE_ENTITY) .contentType(MediaType.APPLICATION_JSON) .bodyValue(errors) .flatMap(response -> response.writeTo(exchange, new ServerResponse.Context() { @Override public List<HttpMessageWriter<?>> messageWriters() { return HandlerStrategies.withDefaults().messageWriters(); } @Override public List<ViewResolver> viewResolvers() { return Collections.emptyList(); } }));
这种方式不需要手动处理DataBuffer和响应完成的逻辑,框架会帮你搞定异步流程。
内容的提问来源于stack exchange,提问作者Hantsy
相关产品推荐
相关产品推荐

