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

Spring Boot中如何捕获ResponseEntityExceptionHandler响应生成JWE?

解决方案:让异常响应也经过JWE加密处理

这个问题我之前也碰到过,核心原因是ResponseEntityExceptionHandler(也就是你的ExceptionResolver)返回的响应,默认情况下可能没被CryptoResponseBodyAdvice正确拦截到。下面给你几个实用的解决方案,你可以根据自己的代码结构来选:

方案一:调整CryptoResponseBodyAdvice的拦截范围与执行顺序

默认的ResponseBodyAdvice可能只针对控制器的@ResponseBody方法生效,我们可以修改它的supports方法,让它覆盖所有ResponseEntity类型的返回(包括异常处理器生成的),同时通过@Order确保它优先执行。

修改后的CryptoResponseBodyAdvice示例:

@ControllerAdvice
@Order(Ordered.HIGHEST_PRECEDENCE) // 确保这个Advice最先执行
public class CryptoResponseBodyAdvice implements ResponseBodyAdvice<Object> {

    // 注入你的JWE加密服务(如果有的话)
    private final JweEncryptionService encryptionService;

    public CryptoResponseBodyAdvice(JweEncryptionService encryptionService) {
        this.encryptionService = encryptionService;
    }

    @Override
    public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
        // 拦截所有ResponseEntity类型,以及带@ResponseBody注解的方法返回
        return ResponseEntity.class.isAssignableFrom(returnType.getParameterType()) 
                || returnType.hasMethodAnnotation(ResponseBody.class);
    }

    @Override
    public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, 
                                 Class<? extends HttpMessageConverter<?>> selectedConverterType, 
                                 ServerHttpRequest request, ServerHttpResponse response) {
        // 处理ResponseEntity类型的响应(异常处理器返回的就是这种)
        if (body instanceof ResponseEntity<?>) {
            ResponseEntity<?> responseEntity = (ResponseEntity<?>) body;
            Object actualBody = responseEntity.getBody();
            if (actualBody == null) {
                return responseEntity; // 如果body为空,直接返回
            }
            // 加密响应体
            String encryptedBody = encryptionService.encryptToJWE(actualBody);
            // 重新包装成ResponseEntity返回
            return new ResponseEntity<>(encryptedBody, responseEntity.getHeaders(), responseEntity.getStatusCode());
        }
        // 处理普通@ResponseBody的响应
        return encryptionService.encryptToJWE(body);
    }
}

这里的关键是:

  • @Order(Ordered.HIGHEST_PRECEDENCE)确保加密逻辑在其他Advice之前执行
  • supports方法明确包含ResponseEntity类型,覆盖异常处理器的返回

方案二:在异常处理器内部直接调用加密逻辑

如果不想修改ResponseBodyAdvice,可以直接在你的ExceptionResolver里,生成异常响应后先加密再返回。这种方式更直接,不需要依赖Advice的拦截逻辑。

修改后的ExceptionResolver示例:

@ControllerAdvice
public class ExceptionResolver extends ResponseEntityExceptionHandler {

    private final JweEncryptionService encryptionService;

    public ExceptionResolver(JweEncryptionService encryptionService) {
        this.encryptionService = encryptionService;
    }

    @Override
    protected ResponseEntity<Object> handleExceptionInternal(Exception ex, Object body, HttpHeaders headers, 
                                                            HttpStatus status, WebRequest request) {
        // 先调用父类方法获取原始异常响应体
        ResponseEntity<Object> originalResponse = super.handleExceptionInternal(ex, body, headers, status, request);
        Object originalBody = originalResponse.getBody();
        
        if (originalBody == null) {
            return originalResponse;
        }
        
        // 加密响应体
        String encryptedBody = encryptionService.encryptToJWE(originalBody);
        // 返回加密后的响应
        return new ResponseEntity<>(encryptedBody, originalResponse.getHeaders(), originalResponse.getStatusCode());
    }

    // 如果你重写了其他handleXXXException方法,也需要在这些方法里添加加密逻辑
    // 比如handleMethodArgumentNotValid等
}

这种方式的好处是逻辑更清晰,异常响应的加密完全由你自己控制,不用担心Advice的拦截优先级问题。

方案三:自定义全局异常处理器替代ResponseEntityExceptionHandler

如果你的异常处理逻辑不需要依赖ResponseEntityExceptionHandler的默认实现,可以自己写一个全局异常处理器,直接在里面生成加密后的响应:

@ControllerAdvice
public class CustomExceptionHandler {

    private final JweEncryptionService encryptionService;

    public CustomExceptionHandler(JweEncryptionService encryptionService) {
        this.encryptionService = encryptionService;
    }

    // 处理所有Exception类型的异常
    @ExceptionHandler(Exception.class)
    public ResponseEntity<String> handleAllExceptions(Exception ex, WebRequest request) {
        // 构建自定义异常响应体
        ErrorResponse errorResponse = new ErrorResponse(HttpStatus.INTERNAL_SERVER_ERROR.value(), ex.getMessage());
        // 加密响应体
        String encryptedBody = encryptionService.encryptToJWE(errorResponse);
        return new ResponseEntity<>(encryptedBody, HttpStatus.INTERNAL_SERVER_ERROR);
    }

    // 可以添加更多针对特定异常的处理方法,比如@ExceptionHandler(MethodArgumentNotValidException.class)
}

这种方式最灵活,完全摆脱了ResponseEntityExceptionHandler的限制,所有异常响应都能被加密处理。

注意事项

  • 不管用哪种方案,都要确保你的加密服务能正确序列化响应体(比如用Jackson把对象转成JSON,再进行JWE加密)
  • 如果响应体是String类型(比如直接返回的错误信息),要注意加密逻辑的兼容性,避免重复加密或者序列化出错

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.14 08:24:43