2023년 7월 8일에 작성되었고, 블로그를 이전하며 옮겨온 포스트입니다.
여기에서 원본을 확인할 수 있습니다.
궁금증
기존에는 웹 개발을 PHP의 프레임워크인 Laravel을 사용하여 개발했다. 하지만, '멋쟁이사자처럼 대학 11기' 동아리에 참여하면서 Spring Boot를 처음 접하게 되었는데, '나는 백엔드를 개발하고 API를 만들면, 대체 프론트엔드에서는 이걸 어떻게 활용하고, 같이 작업하는 걸까?' 라는 의문이 생겼다. 그래서 찾아본 결과, Spring Boot와 React를 연결할 수 있었고, 이를 이용해서 API를 요청, 반환하여 데이터를 주고 받는 방법을 사용하고 있다는 것에 대해 알게되었다.
작업 환경
Java 11
macOS Monterey 12.6
Spring Boot 2.5.6
전체 과정
- Spring Boot 프로젝트 생성
- React 프로젝트 생성
- Spring Boot와 React 간 Proxy 설정
React 프로젝트 생성하기
터미널을 켜고, 'src/main' 폴더 아래에 'frontend' React 프로젝트를 설치한다.
cd src/main
npx create-react-app frontend
설치가 완료되었다면, 위와 같은 구조로 React 프로젝트 파일이 설치된다. 이 과정까지는 대략 2분정도 소요되었다.
React 실행하기
이제 React 프로젝트의 설정을 마쳤으니 'src/main/frontend' 폴더에서 리엑트 프로젝트를 실행해준다.
cd src/main/frontend
npm start
위 명령어를 실행하면, 리엑트 프로젝트가 실행되는 과정이 보이면서, http://localhost:3000 웹 페이지가 자동으로 열린다.

위 페이지가 보인다면, 성공! 물론, 설치한 리엑트 버전에 따라 초기 페이지는 다를 수 있지만 페이지가 표시된다면, 리엑트 프로젝트가 잘 설치된 것이다.
의문 및 해결
그럼 여기서 이상한(?) 점이 React의 웹 페이지 접근 포트는 3000으로 되어있지만, Spring Boot의 접근 포트는 8080이다. 이와 같이 만약, Spring Boot와 React가 같은 포트로 동작하지 않는다면, CORS 오류가 발생한다. CORS 오류란, Cross Origin Resource Sharing, 다른 출처 리소스 공유 정책이다. 간단히 말해서, 같은 도메인 및 서버에서 동작하고 있다면 서로 리소스를 공유하고 있지만, 다른 도메인에서 동작하고 있다면 서로 리소스를 공유할 수 없는 것이다. 그렇기 때문에 Spring Boot와 React가 같은 포트에서 동작할 수 있도록, Proxy 설정을 해야한다.
Proxy 설정
Proxy 설정에 사용되는 방법은 React 공식 문서에 나와 있는 방법인데, 문서는 https://create-react-app.dev/docs/proxying-api-requests-in-development/ 에서 확인할 수 있다. 'src/main/frontend/package.json' 파일에 아래의 코드를 추가한다.
...
"proxy": "http://localhost:8080",
...
테스트
프록시 설정을 완료했으니, 테스트를 하기 위해 src/main/java/com.springboot.test/controller 아래에 'TestController'을 생성한다. 그 후, "Test" 문자를 반환하는 초간단한 API를 하나 만들었다.
@RestController
public class TestController {
@GetMapping("/api/test")
public String test() {
return "Test";
}
}

Spring Boot 프로젝트를 실행하고, http://localhost:8080/api/test에 접속하면, 위와 같이 정상적으로 작동하는 것을 볼 수 있다. 이제 리엑트에서도 이 API 사용이 가능해야 하기 때문에, 'src/main/frontend/src/App.js'에 아래 코드를 추가하여 실행한다.
import logo from './logo.svg';
import './App.css';
import {useEffect, useState} from "react";
function App() {
const [data, setData] = useState(null);
useEffect(() => {
const fetchData = async () => {
try {
const response = await fetch('/api/test');
const result = await response.text();
setData(result);
} catch (error) {
console.error('Error fetching data:', error);
}
};
fetchData();
}, []);
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<p>
Edit <code>src/App.js</code> and save to reload.
</p>
<a
className="App-link"
href="https://reactjs.org"
target="_blank"
rel="noopener noreferrer"
>
Learn React
</a>
{data ? (
<p>
{data}
</p>
) : (
<p>Loading data...</p>
)}
</header>
</div>
);
}
export default App;
위 코드를 붙여넣고, 'src/main/frontend'에서 npm start 명령어를 사용하여 React 프로젝트의 서버도 실행한다.
이 때 주의해야 할 점은, Spring Boot의 프로젝트도 동작하는 상태이고, React 프로젝트도 동작하는 상태여야 정상적으로 실행된다.

http://localhost:3000 페이지에 접속해 보면, 위와 같이 'Learn React' 아래에 테스트로 만들었던 API의 반환 값인 'Test'를 확인할 수 있고, 이를 통해 Spring Boot와 React 간 Proxy 설정이 완료되었음을 확인할 수 있다.
마지막으로
동아리 때문에 React와 Spring Boot를 연결하는 방법에 대해 알아본 것도 맞지만, 개인적으로 토이 프로젝트를 만들 때 Thymeleaf를 사용하고 있었는데, 데이터를 주고 받기 복잡할 뿐더러 개발 시간도 더 많이 걸리는 것 같은 느낌이 들어 React를 사용하여 프론트엔드와 백엔드를 확실하게 구분하는 것이 좋다고 생각하여 꼭 한 번 정리하고 넘어가고 싶었다. React도 한 번 제대로 학습하고, 사용해서 프론트엔드, 백엔드 둘 다 내가 해서 토이 프로젝트를 만들어보고 싶었다.
'Backend' 카테고리의 다른 글
| nGrinder 성능 테스트 #2 - 'Performance Test' 설정 속성 알아보기 (0) | 2026.08.22 |
|---|---|
| nGrinder 성능 테스트 #1 - 시작하기 (0) | 2026.08.22 |
| CI/CD란 무엇일까? (0) | 2026.08.22 |