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

Spring Boot Webflux如何自定义URISyntaxException异常响应

问题根因

你遇到的拦截失效问题核心原因是:URISyntaxException 属于HTTP请求底层URI解析阶段抛出的异常,发生在请求进入Spring WebFlux的Controller处理链路之前。

  • @RestControllerAdvice 仅对Controller方法执行链路内抛出的异常生效,这类早期容器级异常根本走不到Advice的拦截范围。
  • 自定义DefaultErrorWebExceptionHandler不生效,通常是两个原因:一是自定义处理器的优先级不够高,没有覆盖Spring默认的异常处理器;二是异常处理逻辑中调用了request.getURI()这类依赖合法URI的方法,会二次抛出异常,导致错误处理流程本身中断,最终返回空响应体。

可落地方案

1. 注册高优先级全局Web异常处理器(必做)

实现WebExceptionHandler接口,将优先级设置为高于Spring默认异常处理器,直接在最外层拦截URI解析异常,注意不要调用会触发URI二次解析的方法:

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.core.annotation.Order;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.WebExceptionHandler;
import reactor.core.publisher.Mono;
import java.net.URISyntaxException;
import java.nio.charset.StandardCharsets;

// 优先级必须高于默认的错误处理器,数值越小优先级越高
@Order(-2)
@Component
public class EarlyRequestExceptionHandler implements WebExceptionHandler {

    private final ObjectMapper objectMapper;
    private final YourTimeUtil util;

    // 构造注入你需要的依赖
    public EarlyRequestExceptionHandler(ObjectMapper objectMapper, YourTimeUtil util) {
        this.objectMapper = objectMapper;
        this.util = util;
    }

    @Override
    public Mono<Void> handle(ServerWebExchange exchange, Throwable ex) {
        // 判定是否为URI解析异常,可在此扩展其他容器级早期异常的处理
        Throwable targetEx = ex.getCause() != null ? ex.getCause() : ex;
        if (targetEx instanceof URISyntaxException) {
            exchange.getResponse().setStatusCode(HttpStatus.BAD_REQUEST);
            exchange.getResponse().getHeaders().setContentType(MediaType.APPLICATION_JSON);

            // 构造自定义响应体,注意不要调用exchange.getRequest().getURI(),会二次抛异常
            Response errorRes = Response.builder()
                    .method(exchange.getRequest().getMethodValue())
                    .requestUri(exchange.getRequest().getPath().value())
                    .status(HttpStatus.BAD_REQUEST.toString())
                    .message("请求URL格式非法,路径参数包含未编码的特殊字符")
                    .timestamp(util.getCurrentTimeInUtc())
                    .errorCode("INVALID_URI_SYNTAX")
                    .debugMessage(targetEx.getMessage())
                    .build();

            byte[] responseBytes;
            try {
                responseBytes = objectMapper.writeValueAsBytes(errorRes);
            } catch (JsonProcessingException e) {
                responseBytes = "{\"message\":\"系统错误\"}".getBytes(StandardCharsets.UTF_8);
            }
            DataBuffer buffer = exchange.getResponse().bufferFactory().wrap(responseBytes);
            return exchange.getResponse().writeWith(Mono.just(buffer));
        }
        // 非目标异常放行给后续异常处理器处理
        return Mono.error(ex);
    }
}

2. 根源规避方案(建议搭配使用)

按照URL RFC规范,路径中出现的特殊字符必须做百分号编码,比如%编码为%25、@编码为%40、^编码为%5E。可以要求客户端传入email路径参数时先做URL编码,从根源避免URI解析阶段报错。


避坑提示

处理这类请求早期解析异常时,禁止调用以下依赖合法URI的请求方法,否则会导致异常处理逻辑本身抛出异常,无法正常返回响应:

  • request.getURI()
  • request.getQueryParams()
  • 所有需要基于解析后URI做路径匹配的方法

直接从request.getPath().value()拿原始请求路径字符串即可。


内容的提问来源于stack exchange,提问作者Gagan

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 15:00:49