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
相关产品推荐
相关产品推荐

