programing

봄철 필터에 발생하는 예외를 관리하는 방법은 무엇입니까?

javaba 2022. 8. 3. 23:04
반응형

봄철 필터에 발생하는 예외를 관리하는 방법은 무엇입니까?

일반적인 방법으로 5xx 에러 코드를 관리하고 싶습니다.구체적으로는 스프링 어플리케이션 전체에 걸쳐 db가 다운된 경우를 가정해 보겠습니다.스택 트레이스 대신 예쁜 에러 json을 원합니다.

에 대해서는, 「」를 하고 있습니다.@ControllerAdvice다른 예외에 대한 클래스 및 이것은 또한 요청 도중에 DB가 중지되는 경우를 포착합니다.하지만 이게 다가 아닙니다. ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★.CorsFilter ★★OncePerRequestFilterdoFilterCannotGetJdbcConnectionException관리되지 않습니다.@ControllerAdvice나는 온라인에서 나를 더 혼란스럽게 만들었던 몇 가지 것들을 읽었다.

그래서 저는 질문이 많습니다.

  • 스텀필필필 장장?? ?????ExceptionTranslationFilter, 이 은 「」만 취급합니다.AuthenticationException ★★★★★★★★★★★★★★★★★」AccessDeniedException
  • 는 나 의 것을 했다.HandlerExceptionResolver하지만, 이 때문에, 관리에는 커스텀 예외가 없기 때문에, 이것보다 더 확실한 방법이 있을 것입니다.하여 try/catch의 .HandlerExceptionResolver(제 예외는 특별한 것이 아닙니다) 하지만 이 응답은 아무것도 반환되지 않습니다.200파운드

이 문제를 해결할 좋은 방법이 있을까요?고마워요.

그래서 제가 한 일은 이렇습니다.

여기서 필터에 대한 기본 사항을 읽고 필터 체인의 첫 번째가 되는 커스텀필터를 생성하여 거기에서 발생할 수 있는 모든 런타임 예외를 포착해야 한다는 것을 알게 되었습니다.그럼 수동으로 json을 생성하여 응답에 넣어야 합니다.

커스텀 필터는 다음과 같습니다.

public class ExceptionHandlerFilter extends OncePerRequestFilter {

    @Override
    public void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        try {
            filterChain.doFilter(request, response);
        } catch (RuntimeException e) {

            // custom error response class used across my project
            ErrorResponse errorResponse = new ErrorResponse(e);

            response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value());
            response.getWriter().write(convertObjectToJson(errorResponse));
    }
}

    public String convertObjectToJson(Object object) throws JsonProcessingException {
        if (object == null) {
            return null;
        }
        ObjectMapper mapper = new ObjectMapper();
        return mapper.writeValueAsString(object);
    }
}

web.xml 했습니다.CorsFilter★★★★★★★★★★★★★★★★★★★★★★★!

<filter> 
    <filter-name>exceptionHandlerFilter</filter-name> 
    <filter-class>xx.xxxxxx.xxxxx.api.controllers.filters.ExceptionHandlerFilter</filter-class> 
</filter> 


<filter-mapping> 
    <filter-name>exceptionHandlerFilter</filter-name> 
    <url-pattern>/*</url-pattern> 
</filter-mapping> 

<filter> 
    <filter-name>CorsFilter</filter-name> 
    <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class> 
</filter> 

<filter-mapping>
    <filter-name>CorsFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

저는 @kopelitsa의 답변을 바탕으로 해결책을 제시하고 싶었습니다.주요 차이점은 다음과 같습니다.

  1. HandlerExceptionResolver.
  2. Java config over XML config 사용

('RestController/Controller'로 이 달린 가.@RestControllerAdvice ★★★★★★★★★★★★★★★★★」@ControllerAdviceㄴ(으)ㄹ 수 있다라는 을 달았습니다.@ExceptionHandler컨트롤러에서 발생하는 예외를 처리합니다.Rest Controller Advice 음음ice 。

@RestControllerAdvice
public class ExceptionTranslator {

    @ExceptionHandler(RuntimeException.class)
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    public ErrorDTO processRuntimeException(RuntimeException e) {
        return createErrorDTO(HttpStatus.INTERNAL_SERVER_ERROR, "An internal server error occurred.", e);
    }

    private ErrorDTO createErrorDTO(HttpStatus status, String message, Exception e) {
        (...)
    }
}

스프링 보안 필터 체인으로 이 동작을 재사용하려면 필터를 정의하고 보안 설정에 연결해야 합니다.필터는 예외를 위에서 정의한 예외 처리로 리다이렉트해야 합니다.다음은 예를 제시하겠습니다.

@Component
public class FilterChainExceptionHandler extends OncePerRequestFilter {

    private final Logger log = LoggerFactory.getLogger(getClass());

    @Autowired
    @Qualifier("handlerExceptionResolver")
    private HandlerExceptionResolver resolver;

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
            throws ServletException, IOException {

        try {
            filterChain.doFilter(request, response);
        } catch (Exception e) {
            log.error("Spring Security Filter Chain Exception:", e);
            resolver.resolveException(request, response, null, e);
        }
    }
}

보안 설정(Security) 설정(Security Configuration)」을 참조해 주세요.이전 필터의 예외는 모두 잡히지 않기 때문에 체인에 너무 일찍 연결해야 합니다. 게 요.LogoutFilter공식 문서에서 기본 필터 체인과 그 순서를 참조하십시오.다음은 예를 제시하겠습니다.

@Configuration
@EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

    @Autowired
    private FilterChainExceptionHandler filterChainExceptionHandler;

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .addFilterBefore(filterChainExceptionHandler, LogoutFilter.class)
            (...)
    }

}

는 이 하여 다시 할 수 있게 되었습니다.ExceptionController""라는 @ControllerAdvise★★★★★★에Exceptions등록된 필터에 던져집니다.

여러 가지가 제, 개인, 개인, 개인, 개인, 개인, 개인, 개인, 개인, 개인, 개인, 개인, 개인, 개인, 개인, 개인, 개인, 개인, 개인, 개인, 개인, 개인, 개인, 개인, 개인, 개인, 개인, 개인, 개인, 개인, 개인, 개인, 개인, 개인, 개인, 개인, 개인, 개인, , 개인, 개인, 개인, 개인, 개인, 개인, 개인, 개인, 개인, 개인, 개인, 개인, 개인, 개인, 개인, 개인, 개인, 개인, 개인, 개인, 개인, 개인, 개인, 개인, 개인, 개인, 개인, 개인, 개인ExceptionController는 고집불통이고 를 복사는 어떤 처리를 가지고 )ExceptionController아름다운 것을 돌려주고 싶다.JSON필터가 아닌 나머지 예외와 마찬가지로 응답합니다.

{
  "status": 400,
  "message": "some exception thrown when executing the request"
}

어쨋든, 나는 그럭저럭 내 돈을 쓸 수 있었다.ExceptionHandler그리고 아래 단계와 같이 약간의 추가 작업을 해야 했습니다.

순서


  1. 예외를 발생시킬 수도 있고 발생시키지 않을 수도 있는 사용자 지정 필터가 있습니다.
  2. 하는 스프링 .@ControllerAdvise MyException : : MyException 트트 i i

샘플코드

//sample Filter, to be added in web.xml
public MyFilterThatThrowException implements Filter {
   //Spring Controller annotated with @ControllerAdvise which has handlers
   //for exceptions
   private MyExceptionController myExceptionController; 

   @Override
   public void destroy() {
        // TODO Auto-generated method stub
   }

   @Override
   public void init(FilterConfig arg0) throws ServletException {
       //Manually get an instance of MyExceptionController
       ApplicationContext ctx = WebApplicationContextUtils
                  .getRequiredWebApplicationContext(arg0.getServletContext());

       //MyExceptionHanlder is now accessible because I loaded it manually
       this.myExceptionController = ctx.getBean(MyExceptionController.class); 
   }

   @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        HttpServletRequest req = (HttpServletRequest) request;
        HttpServletResponse res = (HttpServletResponse) response;

        try {
           //code that throws exception
        } catch(Exception ex) {
          //MyObject is whatever the output of the below method
          MyObject errorDTO = myExceptionController.handleMyException(req, ex); 

          //set the response object
          res.setStatus(errorDTO .getStatus());
          res.setContentType("application/json");

          //pass down the actual obj that exception handler normally send
          ObjectMapper mapper = new ObjectMapper();
          PrintWriter out = res.getWriter(); 
          out.print(mapper.writeValueAsString(errorDTO ));
          out.flush();

          return; 
        }

        //proceed normally otherwise
        chain.doFilter(request, response); 
     }
}

으로 '스프링 '를 입니다.Exception필터레벨로 , 에 사용하고 )는, 「」( 「필터」레벨로 던져지지 않는 예외)입니다.

//sample SpringController 
@ControllerAdvice
public class ExceptionController extends ResponseEntityExceptionHandler {

    //sample handler
    @ResponseStatus(value = HttpStatus.BAD_REQUEST)
    @ExceptionHandler(SQLException.class)
    public @ResponseBody MyObject handleSQLException(HttpServletRequest request,
            Exception ex){
        ErrorDTO response = new ErrorDTO (400, "some exception thrown when "
                + "executing the request."); 
        return response;
    }
    //other handlers
}

ExceptionController★★★★★★에Exceptions필터에 던져집니다.

위의 답변들을 종합해서 제가 한 일은 다음과 같습니다.우리는 이미 한 잔 했다고요.GlobalExceptionHandler'어느 정도'라는 주석이 붙어 .@ControllerAdvice필터에서 발생하는 예외를 처리하기 위해 코드를 재사용하는 방법도 찾고 싶었습니다.

찾을 수 있는 가장 간단한 해결책은 예외 핸들러를 그대로 두고 다음과 같이 오류 컨트롤러를 구현하는 것입니다.

@Controller
public class ErrorControllerImpl implements ErrorController {
  @RequestMapping("/error")
  public void handleError(HttpServletRequest request) throws Throwable {
    if (request.getAttribute("javax.servlet.error.exception") != null) {
      throw (Throwable) request.getAttribute("javax.servlet.error.exception");
    }
  }
}

로 인해 '예외로 인한 오류'를 합니다.ErrorController는 예외 핸들러로 .@Controller하지 않음)는 모두 문맥을 합니다.ErrorController수정 없이.

이게 정말 나쁜 생각인 이유라도 있나요?

일반적인 방법을 사용하는 경우 web.xml에서 오류 페이지를 정의할 수 있습니다.

<error-page>
  <exception-type>java.lang.Throwable</exception-type>
  <location>/500</location>
</error-page>

Spring MVC에 매핑 추가:

@Controller
public class ErrorController {

    @RequestMapping(value="/500")
    public @ResponseBody String handleException(HttpServletRequest req) {
        // you can get the exception thrown
        Throwable t = (Throwable)req.getAttribute("javax.servlet.error.exception");

        // customize response to what you want
        return "Internal server error.";
    }
}

이것은 기본 Spring Boot/error 핸들러를 덮어쓰는 솔루션입니다.

package com.mypackage;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.web.ErrorAttributes;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.util.Assert;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Map;

/**
 * This controller is vital in order to handle exceptions thrown in Filters.
 */
@RestController
@RequestMapping("/error")
public class ErrorController implements org.springframework.boot.autoconfigure.web.ErrorController {

    private final static Logger LOGGER = LoggerFactory.getLogger(ErrorController.class);

    private final ErrorAttributes errorAttributes;

    @Autowired
    public ErrorController(ErrorAttributes errorAttributes) {
        Assert.notNull(errorAttributes, "ErrorAttributes must not be null");
        this.errorAttributes = errorAttributes;
    }

    @Override
    public String getErrorPath() {
        return "/error";
    }

    @RequestMapping
    public ResponseEntity<Map<String, Object>> error(HttpServletRequest aRequest, HttpServletResponse response) {
        RequestAttributes requestAttributes = new ServletRequestAttributes(aRequest);
        Map<String, Object> result =     this.errorAttributes.getErrorAttributes(requestAttributes, false);

        Throwable error = this.errorAttributes.getError(requestAttributes);

        ResponseStatus annotation =     AnnotationUtils.getAnnotation(error.getClass(), ResponseStatus.class);
        HttpStatus statusCode = annotation != null ? annotation.value() : HttpStatus.INTERNAL_SERVER_ERROR;

        result.put("status", statusCode.value());
        result.put("error", statusCode.getReasonPhrase());

        LOGGER.error(result.toString());
        return new ResponseEntity<>(result, statusCode) ;
    }

}

제공된 다른 훌륭한 답변을 보완하기 위해 최근 컨트롤러 메서드에서 발생할 수 있는 예외와 함께 예외를 발생시킬 수 있는 필터를 포함하는 단순한 SpringBoot 앱에 단일 오류/예외 처리 컴포넌트를 원했기 때문입니다.

다행히 컨트롤러 어드바이스를 스프링 기본 에러 핸들러 덮어쓰기와 조합하여 일관된 응답 페이로드 제공, 로직 공유, 필터로부터의 예외 검사, 특정 서비스 스라운 예외 트랩 등을 할 수 있습니다.

예.


@ControllerAdvice
@RestController
public class GlobalErrorHandler implements ErrorController {

  @ResponseStatus(HttpStatus.BAD_REQUEST)
  @ExceptionHandler(ValidationException.class)
  public Error handleValidationException(
      final ValidationException validationException) {
    return new Error("400", "Incorrect params"); // whatever
  }

  @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
  @ExceptionHandler(Exception.class)
  public Error handleUnknownException(final Exception exception) {
    return new Error("500", "Unexpected error processing request");
  }

  @RequestMapping("/error")
  public ResponseEntity handleError(final HttpServletRequest request,
      final HttpServletResponse response) {

    Object exception = request.getAttribute("javax.servlet.error.exception");

    // TODO: Logic to inspect exception thrown from Filters...
    return ResponseEntity.badRequest().body(new Error(/* whatever */));
  }

  @Override
  public String getErrorPath() {
    return "/error";
  }

}

응용 프로그램 상태를 테스트하고 싶을 때 HTTP 오류 반환 시 필터를 제안합니다.다음 필터는 모든 HTTP 요청을 처리합니다.javax 필터를 사용한 Spring Boot의 최단 솔루션.

구현에는 다양한 조건이 있습니다.이 경우 application Manager는 응용 프로그램이 준비되었는지 테스트합니다.

import ...ApplicationManager;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.servlet.*;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@Component
public class SystemIsReadyFilter implements Filter {

    @Autowired
    private ApplicationManager applicationManager;

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {}

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        if (!applicationManager.isApplicationReady()) {
            ((HttpServletResponse) response).sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE, "The service is booting.");
        } else {
            chain.doFilter(request, response);
        }
    }

    @Override
    public void destroy() {}
}

위의 답변에서 제시된 여러 가지 방법을 읽고 커스텀 필터를 사용하여 인증 예외를 처리하기로 했습니다.다음과 같은 방법으로 에러 응답 클래스를 사용하여 응답 상태와 코드를 처리할 수 있었습니다.

커스텀 필터를 만들고 addFilterAfter 메서드를 사용하여 보안 설정을 변경하여 CorsFilter 클래스 뒤에 추가합니다.

@Component
public class AuthFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
    //Cast the servlet request and response to HttpServletRequest and HttpServletResponse
    HttpServletResponse httpServletResponse = (HttpServletResponse) response;
    HttpServletRequest httpServletRequest = (HttpServletRequest) request;

    // Grab the exception from the request attribute
    Exception exception = (Exception) request.getAttribute("javax.servlet.error.exception");
    //Set response content type to application/json
    httpServletResponse.setContentType(MediaType.APPLICATION_JSON_VALUE);

    //check if exception is not null and determine the instance of the exception to further manipulate the status codes and messages of your exception
    if(exception!=null && exception instanceof AuthorizationParameterNotFoundException){
        ErrorResponse errorResponse = new ErrorResponse(exception.getMessage(),"Authetication Failed!");
        httpServletResponse.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
        PrintWriter writer = httpServletResponse.getWriter();
        writer.write(convertObjectToJson(errorResponse));
        writer.flush();
        return;
    }
    // If exception instance cannot be determined, then throw a nice exception and desired response code.
    else if(exception!=null){
            ErrorResponse errorResponse = new ErrorResponse(exception.getMessage(),"Authetication Failed!");
            PrintWriter writer = httpServletResponse.getWriter();
            writer.write(convertObjectToJson(errorResponse));
            writer.flush();
            return;
        }
        else {
        // proceed with the initial request if no exception is thrown.
            chain.doFilter(httpServletRequest,httpServletResponse);
        }
    }

public String convertObjectToJson(Object object) throws JsonProcessingException {
    if (object == null) {
        return null;
    }
    ObjectMapper mapper = new ObjectMapper();
    return mapper.writeValueAsString(object);
}
}

SecurityConfig 클래스

    @Configuration
    public class JwtSecurityConfig extends WebSecurityConfigurerAdapter {
    @Autowired
    AuthFilter authenticationFilter;
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.addFilterAfter(authenticationFilter, CorsFilter.class).csrf().disable()
                .cors(); //........
        return http;
     }
   }

ErrorResponse 클래스

public class ErrorResponse  {
private final String message;
private final String description;

public ErrorResponse(String description, String message) {
    this.message = message;
    this.description = description;
}

public String getMessage() {
    return message;
}

public String getDescription() {
    return description;
}}

캐치 블록 내에서 다음 방법을 사용할 수 있습니다.

response.sendError(HttpStatus.UNAUTHORIZED.value(), "Invalid token")

임의의 HttpStatus 코드와 커스텀메시지를 사용할 수 있습니다.

webflux에서도 같은 문제가 발생했는데, 누군가가 @ControllerAdvice에서 재사용을 검토하고 있다는 주제에서 직접 예외를 발생시키거나 웹 필터에서 모노 오류를 반환하는 것은 원치 않지만 응답을 모노 오류로 설정하려고 합니다.

    public class YourFilter implements WebFilter {


    @Override
    public Mono<Void> filter(final ServerWebExchange exchange, final WebFilterChain chain) {
        exchange.getResponse().writeWith(Mono.error(new YouException()));
        return chain.filter(exchange)
    }
}

돼요.@ControllerAdvice ★★★★★★★★★★★★★★★★★」@RestControllerAdvice인증 실행 시 발생할 수 있는 예외를 처리합니다.디스패처 서비스렛을 사용하다

  1. 우리가 가질 필요가 있

    HttpServletResponse httpResponse(HttpServletResponse)반응 초기 조향 순간을.

는 '응답'에서 합니다.public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)GenericFilterBean.java) 하여 오류 모델 개체를 출력 스트림에 할 수 2)우리 중이거나 인쇄는 ServletResponse 출력 스트림에 오류 JSON모델 또는 String개체를 쓰는 아래의 유틸리티 클래스를 사용할 수 있다.

public static void handleUnAuthorizedError(ServletResponse response,Exception e)
{
    ErrorModel error = null;
    if(e!=null)
        error = new ErrorModel(ErrorCodes.ACCOUNT_UNAUTHORIZED, e.getMessage());
    else
        error = new ErrorModel(ErrorCodes.ACCOUNT_UNAUTHORIZED, ApplicationConstants.UNAUTHORIZED);
    
    JsonUtils jsonUtils = new JsonUtils();
    HttpServletResponse httpResponse = (HttpServletResponse) response;
    httpResponse.setContentType(MediaType.APPLICATION_JSON_VALUE);
    httpResponse.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
    try {
        httpResponse.getOutputStream().println(jsonUtils.convertToJSON(error));
    } catch (IOException ex) {
        ex.printStackTrace();
    }
}


public String convertToJSON(Object inputObj) {
        ObjectMapper objectMapper = new ObjectMapper();
        String orderJson = null;
        try {
            orderJson = objectMapper.writeValueAsString(inputObj);
        }
        catch(Exception e){
            e.printStackTrace();
        }
        return orderJson;
    }

이에 대한 사용자 지정 필터를 생성하지 않아도.우리는 ServletException(는 doFilter 메서드에서, 그 선언에 나타나 throw 됩니다)를 확장시키는 사용자 지정 예외를 만듦으로써 이것 풀었다.이들과 우리의 국제적 오류 처리기에서 처리하기도 합니다.

편집:문법

왜냐하면 @ ControllerAdvice works 것 같으면 올바른 예외를 잡는 것은 이상하다는 거죠?

@ControllerAdvice
public class GlobalDefaultExceptionHandler {

    @ResponseBody
    @ExceptionHandler(value = DataAccessException.class)
    public String defaultErrorHandler(HttpServletResponse response, DataAccessException e) throws Exception {
       response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value());
       //Json return
    }
}

두꺼비와 500오류가 이러한처럼 뭔가를 주CorsFilter에 이 예외를 catch 하는 데 노력한다.

@ExceptionHandler(DataAccessException.class)
@ResponseBody
public String handleDataException(DataAccessException ex, HttpServletResponse response) {
    response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value());
    //Json return
}

언급URL:https://stackoverflow.com/questions/34595605/how-to-manage-exceptions-thrown-in-filters-in-spring

반응형