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

Spring中如何仅针对Controller特定方法处理ClientAbortException

实现仅指定Controller方法处理ClientAbortException

针对需求——让ReportResource中的with方法处理ClientAbortException,而without方法不处理,有以下几种可行方案:

方案一:在目标方法内部捕获异常

直接在with方法中通过try-catch捕获ClientAbortException,仅对该方法生效;without方法保持原样,抛出的异常交由全局处理器或容器默认逻辑处理。

修改后的with方法代码:

@PostMapping("with")
public ResponseEntity with(@RequestBody FindReport findReport) {
    try {
        return ResponseEntity.ok(reportApplicationService.createReport(findReport));
    } catch (ClientAbortException e) {
        // 执行原异常处理器的日志逻辑
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        final String message = "ClientAbortException generated by request {} {} from remote address {} with X-FORWARDED-FOR {}";
        final String headerXFF = request.getHeader("X-FORWARDED-FOR");
        log.warn(message, request.getMethod(), request.getRequestURL(), request.getRemoteAddr(), headerXFF);
        // 客户端已断开,返回空响应即可
        return ResponseEntity.noContent().build();
    } catch (Exception e) {
        // 处理其他异常,按需抛出或封装
        throw new RuntimeException(e);
    }
}

同时删除原Controller中的@ExceptionHandler(ClientAbortException.class)方法即可。

方案二:在异常处理器中添加路径判断

保留原@ExceptionHandler方法,但在方法内判断请求路径,仅处理来自/api/report/with的请求,其他路径的异常重新抛出。

修改后的异常处理器代码:

@ExceptionHandler(ClientAbortException.class)
public void handleLockException(ClientAbortException exception, HttpServletRequest request) {
    // 判断请求是否来自with接口
    if (request.getRequestURI().endsWith("/api/report/with")) {
        final String message = "ClientAbortException generated by request {} {} from remote address {} with X-FORWARDED-FOR {}";
        final String headerXFF = request.getHeader("X-FORWARDED-FOR");
        log.warn(message, request.getMethod(), request.getRequestURL(), request.getRemoteAddr(), headerXFF);
    } else {
        // 非with接口的异常,重新抛出交由上层处理
        throw exception;
    }
}

注意:如果项目有上下文路径,需要调整URI的判断逻辑以确保匹配准确。

方案三:拆分Controller到不同类

将with和without方法拆分到两个独立的Controller中,仅在包含with方法的Controller中添加@ExceptionHandler处理逻辑。

拆分后的代码示例:

// 处理with接口的Controller,包含异常处理器
@Slf4j
@RestController
@AllArgsConstructor
@RequestMapping(value = "/api/report", produces = MediaType.APPLICATION_JSON_VALUE)
public class ReportWithExceptionController {

    private ReportApplicationService reportApplicationService;

    @PostMapping("with")
    public ResponseEntity with(@RequestBody FindReport findReport) throws Exception {
        return ResponseEntity.ok(reportApplicationService.createReport(findReport));
    }

    @ExceptionHandler(ClientAbortException.class)
    public void handleLockException(ClientAbortException exception, HttpServletRequest request) {
        final String message = "ClientAbortException generated by request {} {} from remote address {} with X-FORWARDED-FOR {}";
        final String headerXFF = request.getHeader("X-FORWARDED-FOR");
        log.warn(message, request.getMethod(), request.getRequestURL(), request.getRemoteAddr(), headerXFF);
    }
}

// 处理without接口的Controller,无自定义异常处理器
@RestController
@AllArgsConstructor
@RequestMapping(value = "/api/report", produces = MediaType.APPLICATION_JSON_VALUE)
public class ReportWithoutExceptionController {

    private ReportApplicationService reportApplicationService;

    @PostMapping("without")
    public ResponseEntity without(@RequestBody FindReport findReport) throws Exception {
        return ResponseEntity.ok(reportApplicationService.createReport(findReport));
    }
}

方案对比

  • 方案一:代码直观,无需额外配置,但业务方法与异常处理逻辑耦合,适合简单场景。
  • 方案二:保持业务方法干净,但依赖路径判断,灵活性较低,路径变更时需同步修改判断逻辑。
  • 方案三:符合单一职责原则,代码结构清晰,但会增加Controller数量,适合接口职责差异较大的场景。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.23 13:35:10