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

Spring过滤器抛出异常时,如何向客户端返回自定义响应?

Spring过滤器抛出异常时返回自定义响应的可行方案

一、直接在过滤器中构建自定义响应(最直接有效)

你之前尝试response.getWriter().write()未生效,大概率是未正确设置响应头,或后续过滤器/框架覆盖了响应内容。正确操作如下:

  1. 清空响应缓冲区,避免默认内容写入
  2. 设置响应状态码、内容类型等必要头信息
  3. 写入自定义响应体
  4. 终止过滤器链,不再调用filterChain.doFilter(request, response)

修改后的过滤器代码:

@Component
public final class MyFilter extends OncePerRequestFilter {

    private TypeA typeA;
    private TypeB typeB;

    public MyFilter(TypeA typeA, TypeB typeB) {
        this.typeA = typeA;
        this.typeB = typeB;
    }

    @Override
    public void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
                                  throws ServletException, IOException {
        if (typeA.getCount() <= 500 || typeB.getCount() <= 400) {
            // 清空已有响应内容
            response.reset();
            // 设置响应头
            response.setStatus(HttpStatus.UNAUTHORIZED.value());
            response.setContentType("application/json;charset=UTF-8");
            // 写入自定义JSON响应
            String customResp = "{\"code\":401,\"message\":\"自定义未授权提示:资源访问受限,请检查配置\",\"path\":\"" + request.getRequestURI() + "\"}";
            response.getWriter().write(customResp);
            // 直接返回,终止过滤器链
            return;
        }
        // 条件满足,继续执行后续过滤器
        filterChain.doFilter(request, response);
    }
}

二、利用Spring Security异常处理器统一处理

你抛出的AccessDeniedException属于Spring Security异常体系,可通过自定义AccessDeniedHandler覆盖默认响应:

  1. 实现自定义AccessDeniedHandler:
@Component
public class CustomAccessDeniedHandler implements AccessDeniedHandler {
    @Override
    public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException e) throws IOException {
        response.reset();
        response.setStatus(HttpStatus.UNAUTHORIZED.value());
        response.setContentType("application/json;charset=UTF-8");
        String customMsg = "{\"code\":401,\"message\":\"" + e.getMessage() + "\",\"path\":\"" + request.getRequestURI() + "\"}";
        response.getWriter().write(customMsg);
    }
}
  1. 修改SecurityConfig配置该处理器:
@EnableWebSecurity
public class SecurityConfig {

    private final CustomAccessDeniedHandler customAccessDeniedHandler;

    public SecurityConfig(CustomAccessDeniedHandler customAccessDeniedHandler) {
        this.customAccessDeniedHandler = customAccessDeniedHandler;
    }

    @Bean
    public SecurityFilterChain mySecurity(HttpSecurity http) throws Exception {
        http.requestMatchers((requests) -> requests.antMatchers("/**"))
                .authorizeHttpRequests((authorize) -> authorize.anyRequest().permitAll())
                // 配置自定义异常处理器
                .exceptionHandling(exceptions -> exceptions.accessDeniedHandler(customAccessDeniedHandler));
        http.csrf().disable();
        return http.build();
    }
}

注意:需确保自定义过滤器处于Spring Security过滤器链之前,可通过@Order注解调整过滤器执行顺序。

三、自定义全局Servlet错误处理(兜底方案)

若上述方法无效,可通过实现ErrorController覆盖全局错误响应(会影响所有错误场景):

@RestController
@RequestMapping("/error")
public class CustomErrorController implements ErrorController {

    private final ErrorAttributes errorAttributes;

    public CustomErrorController(ErrorAttributes errorAttributes) {
        this.errorAttributes = errorAttributes;
    }

    @GetMapping
    public ResponseEntity<Map<String, Object>> handleError(HttpServletRequest request) {
        Map<String, Object> errorDetails = errorAttributes.getErrorAttributes(request, ErrorAttributeOptions.defaults());
        // 修改默认响应字段
        errorDetails.put("message", "自定义全局错误提示");
        errorDetails.remove("error");
        int status = (int) errorDetails.get("status");
        return new ResponseEntity<>(errorDetails, HttpStatus.valueOf(status));
    }
}

你之前方法无效的原因

  • @ControllerAdvice和@ExceptionHandler:仅处理DispatcherServlet之后(控制器层)的异常,过滤器在DispatcherServlet之前执行,无法捕获。
  • response.sendError():会触发Servlet容器的错误页面机制,最终被Spring默认错误处理器覆盖,看不到自定义消息。
  • Baeldung方案:大概率是未正确调整过滤器顺序,导致自定义过滤器抛出的异常未进入Spring Security的异常处理流程。

内容的提问来源于stack exchange,提问作者gai-jin

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.18 07:50:28