# EAPIM 에러 응답 포맷 통일 작업 히스토리

## 작업 배경

### 목표
모든 HTTP 에러 응답을 다음과 같은 표준 JSON 포맷으로 통일:
```json
{"error":"에러코드","error_description":"에러메시지"}
```

## 변경 내역

### 1. MessageUtil 에러 포맷 정의
**파일**: `elink-online-common/src/main/java/com/eactive/eai/common/util/MessageUtil.java`

- 표준 에러 응답 포맷 정의
  ```java
  public static final String ERROR_MESSAGE_DEFAULT_FORMAT = "{\"error\":\"%s\",\"error_description\":\"%s\"}";
  ```

- 에러 코드 상수 추가
  ```java
  public static final String ERROR_CODE_AP_ERROR = "E.GW.AP_ERROR";
  public static final String ERROR_CODE_AUTH_FAIL = "E.GW.AUTH_FAIL";
  public static final String ERROR_CODE_SERVICE_NOT_FOUND = "E.GW.SERVICE_NOT_FOUND";
  ```

- 에러 메시지 생성 메서드
  ```java
  public static String makeJsonErrorMessage(String code, String msg)
  public static String makeJsonErrorMessage(String code, String msg, String errorFormat)
  ```

### 2. 전역 ExceptionHandler 추가
**파일**: `src/main/java/com/eactive/eai/authserver/config/WebMvcConfig.java` (신규 생성)

Spring MVC 전역 예외 처리를 위한 `@ControllerAdvice` 클래스 추가

**처리하는 예외**:
- `HttpMessageNotReadableException` - HTTP 메시지 파싱 실패
- `MethodArgumentNotValidException` - 유효성 검증 실패
- `MissingServletRequestParameterException` - 필수 파라미터 누락
- `BindException` - 바인딩 에러
- `NoHandlerFoundException` - 404 Not Found (핸들러 없음)
- `AuthenticationException` - 401 Unauthorized (인증 실패)
- `AccessDeniedException` - 403 Forbidden (권한 없음)
- `Exception` - 500 Internal Server Error (기타 예외)

**동작 방식**:
1. 예외 발생 시 적절한 HTTP 상태 코드 설정
2. request에 `_authServerStatusCode`, `errorMessage` 속성 설정
3. `/error.jsp`로 forward하여 표준 JSON 응답 생성

### 3. error.jsp 수정
**파일**: `WebContent/error.jsp`

**변경 사항**:
- 기존 HTML 에러 페이지를 JSON 응답으로 변경
- `MessageUtil.makeJsonErrorMessage()` 호출하여 표준 포맷 응답 생성
- HTTP 상태 코드에 따른 에러 코드 매핑:
  - 401 → `ERROR_CODE_AUTH_FAIL`
  - 404 → `ERROR_CODE_SERVICE_NOT_FOUND`
  - 기타 → `ERROR_CODE_AP_ERROR`

```jsp
Integer statusCode = (Integer) request.getAttribute("_authServerStatusCode");
if (statusCode != null) {
    response.setStatus(statusCode);
}

String code;
if (statusCode != null && statusCode == 401) {
    code = MessageUtil.ERROR_CODE_AUTH_FAIL;
} else if (statusCode != null && statusCode == 404) {
    code = MessageUtil.ERROR_CODE_SERVICE_NOT_FOUND;
} else {
    code = MessageUtil.ERROR_CODE_AP_ERROR;
}

String message = (String)request.getAttribute("errorMessage");
String jsonErrorMessage = MessageUtil.makeJsonErrorMessage(code, message);
out.println(jsonErrorMessage);
```

### 4. WebSecurityConfig 에러 처리 추가
**파일**: `src/main/java/com/eactive/eai/authserver/config/WebSecurityConfig.java`

**변경 사항**:
- Spring Security 레벨의 인증/권한 에러 처리 추가
- `authenticationEntryPoint`: 401 Unauthorized → error.jsp 포워딩
- `accessDeniedHandler`: 403 Forbidden → error.jsp 포워딩
- `/error.jsp` 접근 허용 설정 추가

### 5. web.xml 설정 추가
**파일**: `WebContent/WEB-INF/web.xml`

**변경 사항**:
- DispatcherServlet에 `throwExceptionIfNoHandlerFound=true` 설정 추가
  ```xml
  <init-param>
      <param-name>throwExceptionIfNoHandlerFound</param-name>
      <param-value>true</param-value>
  </init-param>
  ```
  → 핸들러 없을 시 `NoHandlerFoundException` 발생하도록 설정

- error-page 매핑 (400, 401, 403, 404, 500 등)
  ```xml
  <error-page>
      <error-code>404</error-code>
      <location>/error.jsp</location>
  </error-page>
  ```
  → Servlet 레벨에서 발생한 에러도 error.jsp로 라우팅

### 6. KjbMGOAuth2Controller 에러 처리 적용
**파일**: `src/main/java/com/eactive/eai/authserver/custom/KjbMGOAuth2Controller.java`

**변경 사항**:
- `JwtAuthException`, 일반 예외 처리 시 `MessageUtil.makeJsonErrorMessage()` 사용
- HTTP 400/401 에러를 표준 포맷으로 반환

### 7. BearerTokenContoller 에러 처리 적용
**파일**: `src/main/java/com/eactive/eai/authserver/custom/BearerTokenContoller.java`

**변경 사항**:
- `MessageUtil` import 추가
- 기존 OAuth2 RFC 6749 에러 포맷을 MessageUtil 표준 포맷으로 변경
- `JwtAuthException`: HTTP 401 + `ERROR_CODE_AUTH_FAIL`
- 일반 예외: HTTP 500 + `ERROR_CODE_AP_ERROR`

### 8. BearerTokenFilter 에러 처리 적용
**파일**: `src/main/java/com/eactive/eai/authserver/custom/BearerTokenFilter.java`

**변경 사항**:
- `MessageUtil` import 추가
- 필터에서 발생하는 에러 응답을 MessageUtil 표준 포맷으로 변경
- `JwtAuthException`: HTTP 401 + `ERROR_CODE_AUTH_FAIL`
- 일반 예외: HTTP 500 + `ERROR_CODE_AP_ERROR`
- JSONObject 직접 생성 방식 제거

### 9. ApiAdapterController 에러 처리 적용
**파일**: `src/main/java/com/eactive/eai/adapter/controller/ApiAdapterController.java`

**변경 사항**:
- Adapter URI를 찾을 수 없는 경우: `ERROR_CODE_SERVICE_NOT_FOUND`
- Adapter를 찾을 수 없는 경우: `ERROR_CODE_AP_ERROR`

## 적용 범위

### 처리되는 에러 시나리오

1. **OAuth2 토큰 발급 실패** (`/mapi/oauth2/token`)
   - 필수 파라미터 누락, 잘못된 grant_type, 인증 실패 등
   - HTTP 400/401 + 표준 JSON 에러 응답

2. **CA Bearer 토큰 발급 실패** (`/auth/oauth/v2/token`)
   - 잘못된 grant_type, 존재하지 않는 client_id, 잘못된 client_secret, scope 오류 등
   - HTTP 401/500 + 표준 JSON 에러 응답

3. **Bearer 토큰 인증 실패** (`/api/auth/*`)
   - 토큰 만료, 잘못된 토큰 등
   - HTTP 401 + 표준 JSON 에러 응답

4. **404 Not Found**
   - 존재하지 않는 API 엔드포인트 호출
   - HTTP 404 + 표준 JSON 에러 응답

5. **400 Bad Request**
   - 잘못된 JSON 포맷, 필수 파라미터 누락 등
   - HTTP 400 + 표준 JSON 에러 응답

6. **403 Forbidden**
   - 권한 없는 리소스 접근
   - HTTP 403 + 표준 JSON 에러 응답

7. **500 Internal Server Error**
   - 서버 내부 오류
   - HTTP 500 + 표준 JSON 에러 응답

## 테스트

테스트 코드는 별도 모듈(`kjb-errors`)에 작성됨.

**테스트 문서**: `kjb-errors/src/test/java/com/eactive/eai/kjb/errors/EAPIM_ExceptionHandler_Test.md`

**주요 테스트**:
- `OAuth2TokenSuccessTest` - OAuth2 토큰 발급 성공
- `OAuth2BearerAuthTest` - Bearer 토큰 인증 성공
- `OAuth2BearerAuth404ErrorTest` - Bearer 토큰 인증 후 404 에러
- `ExceptionHandler400ErrorTest` - 400 에러 응답 검증
- `ExceptionHandler404ErrorTest` - 404 에러 응답 검증
- `ExceptionHandlerSuccessTest` - 일반 API 정상 응답
- `BearerTokenSuccessTest` - CA Bearer 토큰 발급 성공
- `BearerTokenErrorTest` - CA Bearer 토큰 발급 에러 (5가지 케이스)
- `BearerTokenFilterErrorTest` - Bearer 토큰 필터 인증 실패

**검증 항목**:
- HTTP 상태 코드 정확성
- 응답 포맷이 `{"error":"...","error_description":"..."}` 형식인지 확인
- 에러 코드가 적절히 매핑되는지 확인

## 에러 코드 매핑

| HTTP Status | Error Code | 설명 |
|-------------|-----------|------|
| 400 | E.GW.AP_ERROR | Bad Request (잘못된 요청) |
| 401 | E.GW.AUTH_FAIL | Unauthorized (인증 실패) |
| 403 | E.GW.AP_ERROR | Forbidden (권한 없음) |
| 404 | E.GW.SERVICE_NOT_FOUND | Not Found (서비스 없음) |
| 500 | E.GW.AP_ERROR | Internal Server Error (서버 오류) |

## 참고 사항

### 주의사항
- `MessageUtil.makeJsonErrorMessage()`는 메시지 내의 특수문자를 JSON escape 처리함
- error.jsp는 JSON 응답만 출력하므로 브라우저에서 HTML로 보이지 않음
- 상태 코드는 실제 HTTP 응답 상태 코드와 일치해야 함
