1. 401로 잡혀버리는 커스텀 안된 예외들 → 잘못된 레거시 로직 수정(1) 문제점(2) 해결책 : 스프링 기본 예외 처리(BasicErrorController) 동작하게 고치기2. 각기 다른 에러 메시지 응답 형식 → 공통 응답 형식 사용3. 각기 다른 예외 커스텀 → 일괄된 방식으로 커스텀4. 일반적이지 않은 상태 코드들 → 상황에 맞는 상태 코드 사용
1. 401로 잡혀버리는 커스텀 안된 예외들 → 잘못된 레거시 로직 수정
(1) 문제점
url이 잘못 됐을 때 스프링 기본 에러로 잡혔어야 할 404가 401 Unauthorized로 잡혀버린다.
또, 예외를 던지기만 하고 handler에서 예외를 잡아주지 않아
스프링 기본 에러로 잡혔어야 할 500도 마찬가지로 401 Unauthorized로 잡혀버린다.
에러 메시지론 “유효하지 않은 토큰입니다.”가 떴다.
즉, 현재 구조에선 예외 처리가 제대로 안 된 경우 스프링 기본 에러로 잡히지 않고 엉뚱한 곳에서 예외로 잡혀버린다.
(2) 해결책 : 스프링 기본 예외 처리(BasicErrorController) 동작하게 고치기
현재 예외 처리가 제대로 안 된 경우, 발생한 예외의 경로를 추적해보면 아래와 같다.
Controller
→ JwtAuthorizationFilter:71 (
chain.doFilter)→ ExceptionHandlerFilter:24 (
chain.doFilter)exceptionHandlerFilter 는 LogoutFilter 전에 있는 필터다.
SecurityConfig:45 (
addFilterBefore(exceptionHandlerFilter(), LogoutFilter.class)여기까진 좋은데… 그럼 왜
AuthenticationEntryPointCustom 에서 이 예외를 낚아채갈까?바로 레거시 코드에서 else문을 썼기 때문이다…..
여기서 else를 지워주면 마법같이 스프링이 기본적으로 제공하는 예외(BasicErrorController)가 뜬다.
잘못된 url을 입력하면 404가 뜨고, 예외를 제대로 잡지 못한 부분은 500이 뜬다.
패스
2. 각기 다른 에러 메시지 응답 형식 → 공통 응답 형식 사용
에러 메시지 응답 형식이 어떤 건 {code, status} 로 나가고, 어떤 건 {code, httpStatus}로 나간다. 통일해주자.
3. 각기 다른 예외 커스텀 → 일괄된 방식으로 커스텀
IllegalArgumentException 같은 기본 예외를 던지고, 후에 일괄적으로 이를 400 같은 커스텀 예외로 변환하는 코드들이 존재한다.
이는 예외 처리의 정확성을 떨어트리고, 서버 내부 오류인지 클라이언트 단의 오류인지 헷갈리게 하는 등 혼란을 줄 수 있다.
이 방식은 없애자. 이 코드들도 커스텀 예외를 던지게 해서, 서버 내부 오류와 커스텀 예외를 구분해주자.
- 참고
4. 일반적이지 않은 상태 코드들 → 상황에 맞는 상태 코드 사용
I_AM_A_TEAPOT 이란 상태 코드를 들어 보았는가..?이름은 정말 귀엽지만, 우리 레거시 코드에선 이 상태 코드를
NOT_FOUND를 써야 할 상황에서 쓰고 있다.왜…. 라는 의문이 드는 일반적이지 않은 상태 코드들은 일반적이게 바꿔주자.
HTTP418 I'm a teapot클라이언트 오류 응답 코드는 서버가 찻주전자이기 때문에 커피 내리기를 거절했다는 것을 의미합니다. 일시적으로 커피가 없는 커피/차 주전자는 대신 503을 반환해야 합니다. 이 오류는 1998년과 2014년 만우절 농담이었던 하이퍼 텍스트 커피 주전자 제어 규약(Hyper Text Coffee Pot Control Protocol)에 대한 참조입니다.일부 웹사이트는 자동화된 쿼리와 같이 처리하고 싶지 않은 요청에 대해 이 응답을 사용합니다.
팀 내 규칙을 정하고 따르자. (클라이언트 분들도 함께 정하면 좋다)
우리 팀은 아래와 같이 설정했다.
Status Code
OK: 200→ 성공적으로 요청을 처리한 경우
CREATED: 201→ 새로운 리소스가 생성된 경우
NO_CONTENT: 204→ body에 담아보낼 게 없는 경우 #삭제API와 관련
BAD_REQUEST: 400→ 매개변수 누락과 같이 오류의 원인이 클라이언트의 요청과 관련된 경우 (쿼리 스트링 관련)
UNAUTHORIZED: 401→ 세션 정보를 제공하지 않았거나 올바르지 않은 세션 정보인 경우 (로그인 제외 모든 API와 관련)
FOR_BIDDEN: 403→ 접근 권한이 없는 경우 (관리자 API와 관련)
NOT_FOUND: 404→ 요청한 URL을 찾을 수 없거나 존재하지 않는 자원인 경우 (쿼리파라미터와 관련)
CONFLICTED: 409→ 중복되는 자원인 경우 (중복검사와 관련)
INTERNAL_SERVER_ERROR: 500

