覆盖 spring-boot 的默认错误处理程序



如何覆盖Spring Boot错误处理的默认输出?当403响应或类似的事情发生时,我想更改显示的默认值。

现在,我在过滤器链的UsernamePasswordAuthenticationFilter之前添加了一个扩展OncePerRequestFilter的类。在我的自定义过滤器中,我检查doFilterInternal方法中的JWT令牌是否过期。

如果它已经过期,我将状态设置为403response.setStatus(HttpStatus.SC_FORBIDDEN);,并写入内容

protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) {
...

if (jwtTokenUtil.isTokenExpired(jwtToken)) {
response.setStatus(HttpStatus.SC_FORBIDDEN);
response.setContentType(MediaType.APPLICATION_JSON_VALUE);
response.getWriter().write(error.toString());
response.getWriter().flush();
response.getWriter().close();
}
...
}

如果我设置了状态代码而不编写内容,那么没有例外,用户会得到正确的状态代码,但内容是由Spring自动创建的。

如果我设置状态代码并编写内容,那么一切实际上都是从用户的角度出发的,但在内部会发生一个异常,讨论响应是如何被写入的。

我想以正确的方式做事;可能有一些类需要覆盖和自定义,这样我就可以根据错误代码自定义内容,但我找不到任何相关信息。

编辑:如果我试图写入主体,这是内部抛出的异常

Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Unable to handle the Spring Security Exception because the response is already committed.] with root cause
org.springframework.security.access.AccessDeniedException: Access is denied
at org.springframework.security.access.vote.AffirmativeBased.decide(AffirmativeBased.java:84) ~[spring-security-core-5.3.3.RELEASE.jar:5.3.3.RELEASE]
at org.springframework.security.access.intercept.AbstractSecurityInterceptor.beforeInvocation(AbstractSecurityInterceptor.java:233) ~[spring-security-core-5.3.3.RELEASE.jar:5.3.3.RELEASE]
at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:123) ~[spring-security-web-5.3.3.RELEASE.jar:5.3.3.RELEASE]
at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:90) ~[spring-security-web-5.3.3.RELEASE.jar:5.3.3.RELEASE]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) ~[spring-security-web-5.3.3.RELEASE.jar:5.3.3.RELEASE]
at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:118) ~[spring-security-web-5.3.3.RELEASE.jar:5.3.3.RELEASE]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) ~[spring-security-web-5.3.3.RELEASE.jar:5.3.3.RELEASE]
at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:137) ~[spring-security-web-5.3.3.RELEASE.jar:5.3.3.RELEASE]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) ~[spring-security-web-5.3.3.RELEASE.jar:5.3.3.RELEASE]
at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:111) ~[spring-security-web-5.3.3.RELEASE.jar:5.3.3.RELEASE]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) ~[spring-security-web-5.3.3.RELEASE.jar:5.3.3.RELEASE]
at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:158) ~[spring-security-web-5.3.3.RELEASE.jar:5.3.3.RELEASE]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) ~[spring-security-web-5.3.3.RELEASE.jar:5.3.3.RELEASE]
at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:63) ~[spring-security-web-5.3.3.RELEASE.jar:5.3.3.RELEASE]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) ~[spring-security-web-5.3.3.RELEASE.jar:5.3.3.RELEASE]
at com.abc.web.config.JwtRequestFilter.doFilterInternal(JwtRequestFilter.java:130) ~[classes/:na]

与其在过滤器中设置响应状态,我建议您创建一个自定义异常,如-TokenExpiredException,并将其放入代码-中的if块中

if (jwtTokenUtil.isTokenExpired(jwtToken)) {
// ... some code ... //
throw new TokenExpiredException("Token Expired");
// ... some code ... //        
}

然后您可以创建一个@ControllerAdvice,它可以作为处理所有异常的中心类。守则中会有明确的关注点。同样可以通过以下方式完成-

您的application.properties文件应该禁用默认的处理程序-

spring.mvc.throw-exception-if-no-handler-found=true

然后你可以创建一个类来处理异常-

@RestControllerAdvice
public class GlobalControllerExceptionHandler extends ResponseEntityExceptionHandler {

@ResponseBody
@ResponseStatus(HttpStatus.FORBIDDEN)
@ExceptionHandler(value = {TokenExpiredException.class})
public ApiResponse handleTokenExpiredException(TokenExpiredException ex, WebRequest request) {
return new ApiResponse(ex.getMessage());
}
}

这里,ApiResponse是一个表示自定义响应消息的类。

最新更新