You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 06:45:22