Projects/[Spring] Payment System Project(02FEB26~

Troubleshooting: 로그인 성공 후 페이지 튕김 및 API 응답 검증 오류 해결

montmer27 2026. 2. 10. 00:29

관련 커밋 링크 : https://github.com/Sungkyunkwan-2/payment-system-project/commit/074d6bb721703b907ee50836fd610df82f490f63

 

fix: FE successfully recognizes profile dto · Sungkyunkwan-2/payment-system-project@074d6bb

+ public ProfileResponse(String email, String customerUid, String name, String phone, double pointBalance) {

github.com

 

1. 문제 현상

  • 사용자가 로그인을 성공하여 쿠키가 정상 생성됨에도 불구하고, 즉시 로그인 페이지로 리다이렉트되는 현상 발생.
  • 개발자 도구 콘솔에 'A listener indicated an asynchronous response...' 에러 및 API 응답 필드 누락 에러 표시.

 

2. 주요 원인 분석

가. 함수 이름 충돌 (Function Overriding)

  • cookie-util.js와 api-handler.js 두 파일 모두에 'getToken', 'setToken', 'removeToken' 함수가 중복 정의되어 있었음.
  • 브라우저 로드 순서상 뒤에 읽힌 api-handler.js의 함수들이 cookie-util.js의 함수들을 덮어씀.
  • api-handler.js의 getToken은 localStorage를 조회하도록 작성되었으나, 실제 토큰은 cookie-util.js에 의해 쿠키에 저장되고 있었기 때문에 null을 반환하며 인증 실패로 처리됨.

 

나. API 응답 스키마 불일치

  • 서버의 공통 응답 형식(ApiResponse) 때문에 실제 데이터가 'data' 필드 안에 감싸져 있어, 루트 수준에서 필드를 찾는 api-validator.js가 필수 필드(email, name 등)를 찾지 못함.
  • DTO의 필드명(username)과 클라이언트 설정파일(yml)의 필드명(name)이 일치하지 않아 검증 오류 발생.

 

3. 해결 방법

가. 인증 로직 통일

  • api-handler.js 파일 상단에 중복으로 정의된 getToken, setToken, removeToken 함수를 모두 삭제함.
  • 이를 통해 모든 인증 체크 로직이 cookie-util.js에서 제공하는 쿠키 기반 함수를 사용하도록 강제함.
// 1. 기존의 localStorage 방식 함수 3개는 삭제하거나 주석 처리
/*
function getToken() { ... }
function setToken(token) { ... }
function removeToken() { ... }
*/

나. 서버 DTO 및 컨트롤러 수정

  • ProfileResponse DTO의 필드명을 'username'에서 'name'으로 변경하여 API 규격과 일치시킴.
@Transactional(readOnly = true)
public ProfileResponse getCurrentUser(String email) {
    User user = userRepository.findByEmail(email).orElseThrow(
            UserNotFoundException::new
    );
    
    return ProfileResponse.builder()
            .email(user.getEmail())
            // 이전 답변에서 제안한 CUST_{userId}_{rand6} 형식을 적용하거나 
            // 현재 사용 중인 방식을 유지하되 필드명은 name으로 매핑
            .customerUid("CUST_" + Math.abs(email.hashCode())) 
            .name(user.getUsername()) // Entity의 username을 DTO의 name에 할당
            .phone(user.getPhone())
            .pointBalance(user.getPointBalance())
            .build();
}
  • 검증기(api-validator.js)가 구조 분석을 쉽게 할 수 있도록, 특정 API(/api/auth/me)에서는 ApiResponse 래퍼를 제거하고 DTO를 직접 반환하도록 변경.
@GetMapping("/me")
public ResponseEntity<ProfileResponse> getCurrentUser(Principal principal) {
    String email = principal.getName();
    
    // ApiResponse로 감싸지 않고 바로 ProfileResponse를 반환
    return ResponseEntity.ok(userService.getCurrentUser(email));
}

다. 리프레시 토큰 로직 보정

api-handler.js에서 토큰 재발급 후 저장할 때, 이름이 바뀐 'saveToken' 함수를 호출하도록 수정하여 쿠키에 정상 반영되도록 함.

// api-handler.js 내부 401 에러 처리 구간

if (newAuthHeader && newAuthHeader.startsWith('Bearer ')) {
    const newToken = newAuthHeader.substring(7);

    // ✅ setToken 대신 saveToken으로 변경 (cookie-util.js의 함수명)
    saveToken(newToken); 

    console.log("✅ 새 액세스 토큰 저장 완료. 원래 요청 재시도 중...");
    return await makeApiRequest(endpointKey, { ...options, isRetry: true });
}

4. 결과 및 주의사항

  • 수정 후 쿠키에서 토큰을 정상적으로 읽어오며, 네비게이션 바에 사용자 이메일이 정상 노출됨.
  • 향후 공통 함수를 추가할 때는 기존 유틸리티 파일에 동일한 이름의 함수가 있는지 반드시 사전 확인 필요.