본문 바로가기
spring

예외 처리시 원하는 예외 응답값이 안오는 경우

by kdozlo 2024. 4. 29.

예외 처리시 원하는 예외 응답값이 안오는 경우

문제 상황

  • 스프링부트 3.2.5, openjdk 21
  • s3 이미지 업로드 api 요청 시 컨트롤러에서 해당 요청을 받아서 S3Util의 업로드 메서드를 실행시키는 과정으로 진행된다. 또한 그 과정에서 spring security를 통해 JwtAuthenticationFilter와 JwtExceptionFilter를 만든 상황이고, 현재 s3 이미지 업로드 api는 permitAll()로 되어 있다.
  • S3에 이미지 객체를 업로드 할때, 버킷명을 잘못 적었을 때의 예외처리를 구현했습니다. 해당 예외시 _INTERNAL_SERVER_ERROR_를 발생시켰는데, _INVALID_TOKEN_가 발생했다.
  • S3Util upoad 코드
@Slf4j
@Component
@RequiredArgsConstructor
public class S3Util {

    private final AmazonS3 amazonS3;

    @Value("${cloud.aws.s3.bucket}")
    private String bucket;

    public String upload(MultipartFile multipartFile, DirectoryType directoryType, Long dirNamePrincipalId) {
        // 이미지 형식의 파일인지 확인
        if(!Objects.requireNonNull(multipartFile.getContentType()).contains("image")) {
            throw new BusinessException(ErrorType.IMAGE_FORMAT_INVALID);
        }

        // 새로운 파일 이름 생성
        String fileName = createFileName(multipartFile, createDirName(directoryType, dirNamePrincipalId));

        //s3 버킷에 이미지 객체 저장
        try {
            amazonS3.putObject(bucket, fileName, multipartFile.getInputStream(), createMetadata(multipartFile));
        } catch (IOException e) {
            log.error("S3Util upload putObject error : ", e);
            throw new BusinessException(ErrorType.INTERNAL_SERVER_ERROR);
        }

        //이미지 객체 url 반환
        return amazonS3.getUrl(bucket, fileName).toString();
    }

    //저장할 파일의 경로 생성
    private String createDirName(DirectoryType directoryType, Long dirNamePrincipalId) {
        return directoryType.getDirNamePrincipal() + "/" + dirNamePrincipalId + "/" + directoryType.getDirNameAttribute();
    }

    //저장할 파일의 메타 데이터 생성
    private ObjectMetadata createMetadata (MultipartFile multipartFile) {
        ObjectMetadata metadata = new ObjectMetadata();
        metadata.setContentLength(multipartFile.getSize());
        metadata.setContentType(multipartFile.getContentType());

        return metadata;
    }

    //저장할 파일의 이름 생성
    private String createFileName(MultipartFile multipartFile, String dirName) {
        return dirName + "/" + UUID.randomUUID() + "_" + multipartFile.getOriginalFilename();
    }
}
  • 요청시 나온 예외 메시지 - INVALID_TOKEN
{
    "code": 401,
    "message": "유효하지 않은 토큰입니다.",
    "status": "UNAUTHORIZED"
}
  • 콘솔 로그

  • 요청시 나온 예외 메시지가 터진 곳 - JwtExceptionFilter
@Slf4j
@Component
public class JwtExceptionFilter extends OncePerRequestFilter {

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

        try {
            filterChain.doFilter(request, response); // 다음 필터로 넘기기
        } catch (Exception e) {
            log.error("JwtExceptionFilter doFilterInternal : ", e);
            setErrorResponse(response, INVALID_TOKEN);
        }
    }

    public void setErrorResponse(HttpServletResponse response, ErrorType errorType) throws IOException {

        response.setContentType(MediaType.APPLICATION_JSON_VALUE);

        Map<String, Object> errors = new HashMap<>();
        errors.put("code", errorType.getHttpStatus().value());
        errors.put("status", errorType.getHttpStatus().name());
        errors.put("message", errorType.getMsg());

        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.writeValue(response.getOutputStream(), errors);
        response.setStatus(errorType.getHttpStatus().value());
    }
}

문제 원인

  • s3 버킷에 이미지 객체 저장시 , 이 예외는 super를 통해 상위 클래스인 Exception까지 타고 올라간다. 그 후 JwtExceptionFilter의 Exception에 잡혀서 _INVALID_TOKEN_이 터지는거였다. 이때 왜 S3Util의 upload에 있는 try catch문에서 안잡히냐 궁금할것이다. 이유는 간단하다. 현재는 IOException만 잡고 있고, s3 버킷 네임 오류를 잡는 AmazonServiceException를 명시하지 않았기 때문이다.

해결 방안

  • JwtExceptionFilter에서 생기는 예외는 모든 예외를 처리 하는 부분이 아니고 JWT 관련 예외만 터져야 함으로 Exception → JwtException으로 바꾸어 준다.
  • s3 버킷에 이미지 객체 저장시 생기는 예외는 좀더 명확하게 IOException → AmazonServiceException | IOException로 해준다. 이때 IOException은 multipartFile.getInputStream() 과정에서 생기는 오류를 잡을 때 사용한다.

다음 포스팅. . .

  • 현재 s3 버킷에 이미지 객체 저장 기능 테스트 과정이라서 유저의 권한은 필요가 없다. 그래서 jwt관련 필터를 거쳐갈 필요가 없다고 생각해서 permitAll로 했는데 웬걸 필터를 지나쳐 가는거였다!! 열받. 결론은 내가 완전 오해한거 였다. 다음글에서 확인해 보시길
    https://kdozlo.tistory.com/34