HttpMessageNotReadableException

Godtaek·2024년 1월 27일
1

Spring

목록 보기
4/9

HttpMessageNotReadableException -> 그러나 Controller에서 정상적으로 받고, 비즈니스 로직이 실행되는....

코드

@PostMapping("/")
public Response<Void> createPost(@RequestBody PostRequest postRequest) {
    postService.createPost(postRequest.getUserEmail(),postRequest.getTitle(), postRequest.getContent());
    return Response.success();
    }

여기가 문제있는 줄 알았다..... 에러코드에 403이 존재하길래, 임의로 PostRequest에 userEmail을 담았다.

에러코드 (너무 길어서 생략)

Failure while trying to resolve exception [org.springframework.http.converter.HttpMessageNotReadableException]

2024-01-27T23:51:43.858+09:00 ERROR 10960 --- [nio-8080-exec-1] o.a.c.c.C.[.[.[/].[dispatcherServlet]    : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed: org.springframework.http.converter.HttpMessageNotReadableException: Required request body is missing: public com.example.alchohol.common.response.Response<java.lang.Void> com.example.alchohol.post.controller.PostController.createPost(com.example.alchohol.post.controller.Request.PostRequest)] with root cause

2024-01-27T23:51:43.865+09:00 ERROR 10960 --- [nio-8080-exec-1] o.a.c.c.C.[.[.[/].[dispatcherServlet]    : Servlet.service() for servlet [dispatcherServlet] threw exception

org.springframework.security.access.AccessDeniedException: Access Denied

2024-01-27T23:51:43.866+09:00 ERROR 10960 --- [nio-8080-exec-1] o.a.c.c.C.[Tomcat].[localhost]           : Exception Processing ErrorPage[errorCode=0, location=/error]

jakarta.servlet.ServletException: Unable to handle the Spring Security Exception because the response is already committed.

문제점

  1. 대부분 해당 에러는 Request 형태가 잘못되었을 때 나타난다. 그러나 내 경우에는 비즈니스 로직까지 정상작동한다.
  2. TokenFilter와 문제가 있나본데, accessDenied도 뜬다.
  3. Response 아니면 TokenFilter의 에러를 가르킨다.
  4. 그래서 tokenfilter 설정을 봤더니...
try {
    final String header = request.getHeader(HttpHeaders.AUTHORIZATION);
    final Optional<String> token = Optional.ofNullable(resolveToken(header));
        
    if (token.isEmpty()) {
        log.error("헤더가 Bearer 로 시작하지 않습니다. {}", request.getRequestURI());
        
        throw new AlcoholException(ErrorCode.INVALID_PERMISSION);
        
    } else {
        Authentication auth = getAuthentication(token.get(), secretKey);
        SecurityContextHolder.getContext().setAuthentication(auth);
        }
    
    filterChain.doFilter(request, response);
} catch (AlcoholException e) {
        log.error(e.getMessage());
}
    
    filterChain.doFilter(request, response);

try문에서 doFilter 한번, 밖에서 doFilter를 한 번하는 게 문제였다.
permitAll 때문에 doFilter를 밖에 뒀는데, try문 안의 doFilter를 지우지 않았다.
(밖의 doFilter가 아니라면, permitAll을 하더라도 filter에 걸린다.)

해결

  1. try문 안의 doFilter를 지웠다.
  2. PostRequest에서 userEmail을 뺐다.
    @PostMapping("/")
    public Response<Void> createPost(@AuthenticationPrincipal User user, @RequestBody PostRequest postRequest) {
        postService.createPost(user.getUserEmail(),postRequest.getTitle(), postRequest.getContent());
        return Response.success();
    }

막간 상식으로 Spring 3.2부터 @AuthenticalPricnipal로 User의 정보를 받는 걸 권장한다고 한다.
(이 때, User는 UserDetails를 구현한 dto다.)

결과는 안정적이었다....

해결하고 난 뒤, 아무것도 아닌 에러였지만 막상 걸려보니 어떻게 검색해야 할지도 막막했던 경험이었다

profile
성장하는 개발자가 되겠습니다

1개의 댓글

comment-user-thumbnail
2024년 4월 9일

으어어 이거보고 오류 찾았습니다 감사합니다 ㅠㅠ

답글 달기