[SPRING] @ExceptionHandler에서 @RequestBody를 얻는 방법 (Spring REST)
SPRING@ExceptionHandler에서 @RequestBody를 얻는 방법 (Spring REST)
나는 spring-web-4.3.3을 포함하는 Spring Boot 1.4.1을 사용하고있다. 서비스 코드에 의해 던진 예외를 처리하기 위해 @ControllerAdvice로 주석 처리 된 클래스와 @ExceptionHandler로 주석 처리 된 메소드가 있습니다. 이러한 예외를 처리 할 때 PUT 및 POST 작업에 대한 요청의 일부인 @RequestBody를 기록하여 내 문제의 원인이되는 요청 본문을 볼 수 있으므로 내 경우에는 진단에 중요합니다.
Spring의 Docs에서 @ExceptionHandler 메소드의 메소드 서명은 HttpServletRequest를 포함하여 다양한 것들을 포함 할 수있다. 요청 본문은 일반적으로 getInputStream () 또는 getReader ()를 통해 여기에서 가져올 수 있지만 내 컨트롤러 메소드가 요청 본문을 "@RequestBody Foo fooBody"와 같이 광산에서 파싱 할 경우 HttpServletRequest의 입력 스트림이나 판독기가 이미 닫혀 있습니다. 내 예외 처리 메서드가 호출 될 때. 기본적으로 요청 본문은 Spring에서 이미 읽었으며 여기에서 설명한 문제와 유사합니다. 서블릿을 사용하여 요청 본문을 한 번만 읽을 수있는 것은 일반적인 문제입니다.
불행히도 @RequestBody는 예외 핸들러 메소드에서 사용할 수있는 옵션 중 하나가 아닙니다. 그렇다면 사용할 수 있습니다.
예외 처리기 메서드에 InputStream을 추가 할 수 있지만 HttpServletRequest의 InputStream과 동일하므로 동일한 문제가 발생합니다.
나 또한 (ServletRequestAttributes) RequestContextHolder.currentRequestAttributes ()로 현재 요청을 얻으려고했다. getRequest ()는 현재 요청을 얻는 또 다른 트릭이지만, 끝내는 HttpServletRequest는 Spring이 예외 처리 메소드에 전달하는 것과 같다. 같은 문제가 있습니다.
필자는이 같은 몇 가지 솔루션에 대해 읽었으며 필터 체인에 사용자 지정 요청 래퍼를 삽입하여 요청의 내용을 읽고이를 한 번 이상 읽을 수 있도록 캐시합니다. 로깅을 구현하기 위해 전체 필터 / 요청 / 응답 체인 (및 잠재적으로 성능 또는 안정성 문제 도입)을 중단하고 싶지 않기 때문에이 솔루션을 좋아하지 않습니다. 업로드 된 문서 (예 : 나는 그렇다), 나는 그것을 메모리에 캐쉬하고 싶지 않다. 게다가 Spring은 아마 @RequestBody를 이미 어딘가에 캐시했을 것입니다.
덧붙여 말하자면, 많은 솔루션은 ContentCachingRequestWrapper Spring 클래스를 사용하는 것을 권장합니다.하지만 제 경험상 이것이 작동하지 않습니다. 문서화되지 않은 것 외에도 소스 코드를 살펴보면 요청 본문이 아니라 매개 변수 만 캐시하는 것처럼 보입니다. 이 클래스에서 요청 본문을 가져 오려고하면 항상 빈 문자열이됩니다.
그래서 내가 놓친 다른 옵션을 찾고 있습니다. 읽어 주셔서 감사합니다.
해결법
-
==============================
1.요청 본문 오브젝트를 요청 범위의 Bean으로 참조 할 수 있습니다. 그런 다음 해당 요청 범위의 bean을 예외 핸들러에 삽입하여 요청 본문 (또는 참조하려는 다른 요청 컨텍스트 bean)을 검색하십시오.
요청 본문 오브젝트를 요청 범위의 Bean으로 참조 할 수 있습니다. 그런 다음 해당 요청 범위의 bean을 예외 핸들러에 삽입하여 요청 본문 (또는 참조하려는 다른 요청 컨텍스트 bean)을 검색하십시오.
// @Component // @Scope("request") @ManagedBean @RequestScope public class RequestContext { // fields, getters, and setters for request-scoped beans } @RestController @RequestMapping("/api/v1/persons") public class PersonController { @Inject private RequestContext requestContext; @Inject private PersonService personService; @PostMapping public Person savePerson(@RequestBody Person person) throws PersonServiceException { requestContext.setRequestBody(person); return personService.save(person); } } @ControllerAdvice public class ExceptionMapper { @Inject private RequestContext requestContext; @ExceptionHandler(PersonServiceException.class) protected ResponseEntity<?> onPersonServiceException(PersonServiceException exception) { Object requestBody = requestContext.getRequestBody(); // ... return responseEntity; } }
-
==============================
2.Accepted answer는 새로운 POJO를 만들어 전달하지만, http 요청을 다시 사용하여 추가 객체를 만들지 않고도 동일한 동작을 얻을 수 있습니다.
Accepted answer는 새로운 POJO를 만들어 전달하지만, http 요청을 다시 사용하여 추가 객체를 만들지 않고도 동일한 동작을 얻을 수 있습니다.
컨트롤러 매핑 예제 코드 :
public ResponseEntity savePerson(@RequestBody Person person, WebRequest webRequest) { webRequest.setAttribute("person", person, RequestAttributes.SCOPE_REQUEST);
그리고 나중에 ExceptionHandler 클래스 / 메소드에서 사용할 수 있습니다 :
@ExceptionHandler(Exception.class) public ResponseEntity exceptionHandling(WebRequest request,Exception thrown) { Person person = (Person) request.getAttribute("person", RequestAttributes.SCOPE_REQUEST);
from https://stackoverflow.com/questions/43502332/how-to-get-the-requestbody-in-an-exceptionhandler-spring-rest by cc-by-sa and MIT license
'SPRING' 카테고리의 다른 글
[SPRING] @Configuration 클래스의 주석으로 구동되는 트랜잭션 설정하기 (0) | 2019.04.15 |
---|---|
[SPRING] 스프링 웹 소켓 데모를 실행할 수 없음 (0) | 2019.04.15 |
[SPRING] Spring에서 'Rejected bean name - URL 경로가 식별되지 않음'을 처리하는 방법? (0) | 2019.04.15 |
[SPRING] 알 수없는 속성에서 PUT 및 POST가 실패 함 Spring 다른 동작 (0) | 2019.04.15 |
[SPRING] 전체 테스트를 트랜잭션없이 각 단위 테스트 후에 데이터베이스 상태를 어떻게 재설정합니까? (0) | 2019.04.15 |