- [React.js] Spring Boot와 연동 시 `Invalid URL` 오류 해결기(리액트 프로젝트 중단점 설정)2025년 06월 18일 21시 44분 01초에 업로드 된 글입니다.작성자: DandyNow728x90반응형
Spring Boot와 React 연동 시
Invalid URL
오류 해결기Spring Boot 백엔드와 React 프런트엔드를 연동하는 과정에서
SyntaxError: Failed to execute 'open' on 'XMLHttpRequest': Invalid URL
이라는 오류를 마주했고, 이를 해결한 과정을 공유하고자 한다. 이 글이 비슷한 문제로 고민하는 분들에게 도움이 되기를 바란다.
1. 문제의 시작:
Cannot read properties of undefined
와 서버 무응답React 애플리케이션에서 로그인 요청을 보냈을 때, 브라우저 콘솔에는
Cannot read properties of undefined (reading 'data')
라는 오류가 나타났다. 동시에 백엔드 Spring Boot 서버의 모니터링 툴에는 아무런 요청도 잡히지 않는 상황이었다.처음에는 다음과 같은 문제들을 의심했다.
- CORS (Cross-Origin Resource Sharing) 문제: 프런트엔드(
http://localhost:3000
)와 백엔드(http://[IP주소]:8080
)의 출처(Origin)가 달라 발생하는 보안 문제일 것이라 생각했다. - 네트워크 또는 방화벽 문제: 특정 IP만 허용하는 외부 방화벽 설정 때문에 요청 자체가 서버에 도달하지 못하는 것이 아닌가 의심했다.
2. 초기 진단: CORS와 방화벽은 범인이 아니다?
2.1. CORS 테스트
브라우저의 CORS 정책을 무력화하기 위해 크롬을
--disable-web-security
옵션으로 실행했다. 하지만 여전히 동일한 오류가 발생했고, 이는 CORS 문제가 아니라는 강력한 증거가 되었다. Postman으로는 요청이 정상적으로 잘 작동하는 것도 CORS 문제가 아님을 시사했다.2.2. 네트워크/방화벽 테스트
ping
테스트: React 앱이 실행 중인 PC에서 서버 IP로ping
을 보냈을 때 요청 시간이 만료되었다. 이는 네트워크 연결에 문제가 있음을 나타내는 듯했다.telnet
테스트: 하지만 서버의 8080 포트가 열려 있다고 확인된 후,telnet [서버 IP] 8080
명령을 실행했을 때 검은색 화면에 커서가 깜빡이는 것을 확인했다. 이는 PC에서 서버의 8080 포트까지 TCP 연결이 성공적이라는 의미이다.ping
실패는 서버 방화벽이 ICMP 프로토콜만 차단하고 있었기 때문이었고, 실제 애플리케이션 통신에 사용되는 TCP는 허용하고 있었던 것이다.
이로써 네트워크 연결 자체는 문제가 없으며, 방화벽도 8080 포트에 대한 접근을 허용하고 있음을 알 수 있었다. 문제는 더 상위 계층에 있을 것이라 판단했다.
3. 진짜 범인:
Invalid URL
오류의 등장네트워크 문제가 아니라는 확신이 들자, 브라우저 개발자 도구의
소스
탭을 자세히 살펴보았다. 그리고 마침내 다음과 같은 결정적인 오류 메시지를 발견했다.SyntaxError: Failed to execute 'open' on 'XMLHttpRequest': Invalid URL
이 오류는
XMLHttpRequest
객체가 HTTP 요청을 열려고 할 때, 전달받은 URL 문자열이 유효하지 않다는 것을 의미한다. 즉, 요청이 서버에 도달하기도 전, 클라이언트(브라우저)에서 요청 객체를 생성하는 단계에서 URL 자체가 잘못되었다는 뜻이다.3.1. 원인 추적: Axios
baseURL
과 상대 경로 조합이 오류 메시지를 바탕으로 Axios 설정과 API 호출 코드를 다시 점검했다.
특히 AxiosbaseURL
과REST.post()
메서드에 전달되는 상대 경로의 조합에 문제가 있을 것이라 추정했다.// React 프로젝트의 Axios 설정 const baseURL = process.env.REACT_APP_API_URL; // .env 파일에서 불러옴 const REST = axios.create({ baseURL, headers: { 'Content-type': 'application/json', }, }); // 로그인 요청 예시 // REST.post('/api/v1/auth/login', credentials);
디버깅을 위해 Axios 요청 인터셉터에
debugger;
를 삽입하고config
객체의 내용을 자세히 살펴보았다.REST.interceptors.request.use( async config => { debugger; // 여기에 중단점 설정 console.log('Request Config:', config); console.log('Final URL being sent:', config.baseURL ? new URL(config.url, config.baseURL).href : config.url); return config; }, error => Promise.reject(error) );
디버깅 결과,
.env
파일에 설정된REACT_APP_API_URL
값(baseURL
)이http://[IP주소]:8080
처럼 마지막에 슬래시(/
)가 누락되어 있었고, API 호출 시REST.post('/api/v1/auth/login', ...)
와 같이 상대 경로가 슬래시로 시작하고 있었다.대부분의 웹 환경에서는
http://[IP주소]:8080/api/v1/auth/login
처럼 자동으로 슬래시가 삽입되어 처리되지만, 특정 환경이나 브라우저, Axios 버전에서는 이를Invalid URL
로 간주하여 오류가 발생했던 것이다.
4. 해결책: 명시적인 슬래시 처리
문제의 원인이
baseURL
의 끝 슬래시 누락과 Axios의 URL 조합 방식이라는 것을 알게 된 후, 해결책은 비교적 간단했다. React 프런트엔드 코드에서 API 요청 시 코드단에서 슬래시를 명시적으로 포함시켜 URL 조합이 항상 올바르게 되도록 했다.예를 들어,
baseURL
이http://[IP주소]:8080
일 때,// 기존 호출 방식 (문제 발생 가능) // REST.post('/api/v1/auth/login', credentials); // 수정된 호출 방식 (항상 올바른 URL 조합) REST.post(`${REST.defaults.baseURL}/api/v1/auth/login`, credentials);
혹은
baseURL
자체를http://[IP주소]:8080/
와 같이 항상 슬래시로 끝나도록.env
파일에서 설정하는 것도 한 가지 방법이다. 하지만 현재 코드에서/
를 직접 추가하는 방식으로 해결했기에, 이는 유연성을 유지하면서 문제를 해결한 좋은 사례가 된다.
5. 결론
이번 문제는 네트워크, 방화벽, CORS 등 여러 가능성을 탐색하는 과정에서
Invalid URL
이라는 핵심적인 단서를 발견하고, Axios의 URL 조합 방식과 환경 변수 설정의 미묘한 차이가 불러온 것이다.ping
,telnet
과 같은 네트워크 진단 도구 사용, 그리고 브라우저 개발자 도구의Network
탭과 코드 디버깅을 통한 단계별 문제 해결 접근 방식이 얼마나 중요한지 다시 한번 깨달았다.비슷한
Invalid URL
오류를 겪고 있다면, Axios의baseURL
과 API 호출 시 전달하는 상대 경로가 올바르게 조합되어 최종적으로 유효한 URL을 형성하는지 꼭 확인해보기를 바란다.728x90반응형'언어·프레임워크 > React.js' 카테고리의 다른 글
[React.js] 네이버 지도 API PDF 변환 시 CORS 오류 완벽 해결법 (0) 2025.06.16 [React.js] 메모이제이션 완벽 가이드: memo, useCallback, useMemo와 Profiler 활용 (0) 2025.05.25 [React.js] `useEffect`와 `useLayoutEffect`의 차이: 깜박임 현상과 중간 값 노출 (0) 2025.05.23 [React.js] 네이버 지도 API 마커 중앙 정렬과 레이어 제어 (0) 2025.05.14 [React.js] Naver 지도 resize 이벤트 오류 해결하기 (`__event_relations__` 에러) (0) 2025.04.30 다음글이 없습니다.이전글이 없습니다.댓글 - CORS (Cross-Origin Resource Sharing) 문제: 프런트엔드(