최근에React로 개발을 진행하면서 가장 큰 특징 중 하나인 SPA(Single Page Application) 환경에서 예상치 못한 문제를 마주쳤다. Apache 서버에 React 애플리케이션을 배포했을 때, 메인 페이지인 '/' 경로는 정상적으로 작동했지만, 다른 경로들에서 404 에러가 발생했다... 😡
이 문제를 해결하기 위해 .htaccess 파일을 사용하게 되었고, 그 과정에서 배운 내용들을 정리해보고자 한다!!!
SPA(Single Page Application)란?
이전 포스팅에서 설명했지만 이 글에서도 SPA에 대한 이해를 다시 한 번 끄집어 내보고자 한다.
SPA는 서버로부터 완전한 새로운 페이지를 불러오지 않고, 현재의 페이지를 동적으로 다시 작성함으로써 사용자와 소통하는 웹 애플리케이션이나 웹사이트를 말한다.
기존의 전통적인 웹사이트는 사용자가 다른 페이지로 이동할 때마다 새로운 HTML을 서버에서 받아왔지만, SPA는 최초에 한 번만 페이지 전체를 로드하고, 이후에는 필요한 데이터만 동적으로 갱신한다.
Apache 서버에서 발생하는 라우팅 문제
아래 코드를 함께 살펴보자.
React Router를 사용하여 클라이언트 측 라우팅을 구현했음에도 불구하고, 아래와 같은 라우팅 설정이 서버에서 제대로 동작하지 않는 문제가 발생했다.
import { BrowserRouter, Routes, Route } from 'react-router-dom';
function App() {
return (
<BrowserRouter>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
<Route path="/products" element={<Products />} />
</Routes>
</BrowserRouter>
);
}
이는 Apache 서버가 요청된 URL을 실제 파일 경로로 해석하려고 시도하기 때문이다.
SPA에서는 모든 라우팅이 클라이언트 측에서 처리되어야 하지만, 서버는 이를 인식하지 못하고 실제 파일을 찾으려고 시도하여 404 에러를 발생시킨다.
.htaccess 파일을 통한 해결 방법
.htaccess 파일은 Apache 웹 서버의 디렉토리별 설정을 제어하는 설정 파일이다.
이 파일을 사용하여 모든 요청을 index.html로 리다이렉트함으로써 SPA의 라우팅 문제를 해결할 수 있다.
React 애플리케이션의 빌드 폴더(build 또는 dist)에 아래와 같은 내용의 .htaccess 파일을 생성해야한다!
Options -MultiViews
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^ index.html [QSA,L]
이 설정의 각 줄이 하는 역할을 살펴보면
- Options -MultiViews: Apache의 MultiViews 옵션을 비활성화한다. 이는 URL과 일치하는 파일을 자동으로 찾는 것을 방지한다.
- RewriteEngine On: URL 재작성 엔진을 활성화한다.
- RewriteCond %{REQUEST_FILENAME} !-f: 요청된 경로가 실제 파일이 아닌 경우에만 규칙을 적용한다.
- RewriteCond %{REQUEST_FILENAME} !-d: 요청된 경로가 실제 디렉토리가 아닌 경우에만 규칙을 적용한다.
- RewriteRule ^ index.html [QSA,L]: 모든 요청을 index.html로 리다이렉트한다. QSA는 쿼리 문자열을 유지하고, L은 이 규칙이 마지막임을 의미한다.
🚨배포 과정에서의 주의사항🚨
React 애플리케이션을 빌드할 때, .htaccess 파일이 build 폴더에 포함되어야 한다.
만약 create-react-app을 사용하고 있다면, public 폴더에 .htaccess 파일을 위치시키면 빌드 시 자동으로 build 폴더에 복사된다.
'React' 카테고리의 다른 글
[React] Footer 스타일링 with Flexbox, 웹에 Footer 적용해보기! (0) | 2025.02.16 |
---|---|
[React] Naver Maps API를 활용한 지도 서비스 구현하기 *마커 커스터마이징 포함!* (1) | 2025.02.15 |
[React] Axios vs Fetch: HTTP 요청 라이브러리 비교 분석 (0) | 2025.02.13 |
[React] 디바운싱을 활용한 검색 최적화 (1) | 2025.02.12 |
[React] Lucide-react로 아이콘 쉽게 쓰기 🤩 (0) | 2025.02.11 |