회사 어드민 프로젝트에 필터 기능을 구현하기 위해 쿼리스트링을 열심히 달던 중이였다. 그런데 정말 귀신이 곡할 노릇으로 새로 고침만 하면 쿼리스트링 부분이 홀랑 날아가버렸다. 아니 이게 무슨 일이냐고. (헛짚은거 같긴 한데) 해시 라우터 니가 범인이니? 아니 그런데 잠깐(…) 이 프로젝트는 도대체 왜 해시 라우터로 되어 있는거지?
(깔깔 포인트: 너무나 당연하게도 해시 라우터는 범인이 아니였다. 그저 어떤 HOC에서 의도치 않게 쿼리스트링을 날려버리는 버그가 있었을 뿐 ^^ 결국 이 문제는 잘 해결했다.)
(… 부끄러운 이야기이지만) 나는 이제껏 경험한 React 프로젝트에서는 모두 Browser Router만을 사용했기 때문에 Hash Router는 친숙하지 않았다.
여러가지 글을 찾아본 결과 두 라우터가 다음과 같은 특징을 갖고 있음을 알 수 있었다.
Browser Router는 HTML5의 History API를 사용하여 페이지 간의 전환을 처리한다. 이 방식은 실제 URL 경로를 사용하므로 http://example.com/about
과 같은 형태의 URL을 가진다. 주요 특징은 다음과 같다.
Hash Router는 URL의 해시(#)를 사용하여 페이지 간의 전환을 처리한다. 예를 들어, http://example.com/#/about
과 같은 형태의 URL을 사용한다. 해시(#)는 URL의 일부로 간주되지만 클라이언트 측에서만 해석되고 서버로의 요청에는 포함되지 않는다. 이는 웹 브라우저의 내장된 기능으로 이러한 특징으로 인해 서버 측에서는 항상 동일한 URL(http://example.com/
)의 요청만을 받게 되고 그 결과 동일한 페이지를 반환하게 된다. 주요 특징은 다음과 같다
http://example.com/#/about
과 http://example.com/#/contact
라는 두 개의 페이지는 실제로는 동일한 기본 URL인 http://example.com/
을 공유한다. 이로 인해 검색 엔진은 각각의 페이지를 별개의 인덱스로 처리하기 어려울 수 있다.대부분의 항목에서 고개를 끄덕이며 읽어 내려오는데, 한 가지 특징에서 의문이 들었다. Browser Router를 사용하면 새로 고침시에 에러가 난다고? 왜?
이제까지 내가 경험했던 React 기반 프로젝트에서는 React Router의 Browser Router를 사용했으나 새로 고침시에 에러가 나는 현상을 만나지 못했었다. 그럼 내가 썼던 Browser Router는 무엇이었을까? (…) 나도 모르게 누군가가 추가적인 세팅을 해 주었던 것일까? (혹시 코드 우렁각시라도 있는 것일까? 🥺) 그 새로고침 에러를 해결하기 위해선 추가적인 세팅이 필요하다고 하는데, 그 추가적인 세팅이란 과연 무엇일까?
우선 Browser Router 를 사용하면 왜 새로 고침시에 에러가 발생 하는지 근본적인 원인을 살펴보고자 했다.
MPA(Multi page Application)으로 구현된 웹사이트의 경우, 경로를 이동하면 다음과 같은 동작을 하게 된다.
www.example.com/about
페이지로 앵커 태그를 통해 이동을 한다.about.html
을 받아온다.about.html
이용해 화면을 그린다.즉, 이 MPA에서 새로운 화면을 보여준다는 것은 = 새로운 html 파일을 받아온다
, 이며 새로운 페이지를 보기 위해서는 새로고침(과 같은 효과)가 일어나야만 했다. 따라서 유저들은 새로운 html 페이지를 받아올 때까지 하얗게 날아간 화면을 봐야만 했다.
그러나 SPA(Single Page Application)방식의 프레임 워크들이 대두되고 CSR을 하게 되면서 라우팅의 동작 방식이 변하게 된다. SPA는 html은 한번만 받아오고 나머지 화면을 전부 JS로 그리는 형태이다. 따라서 SPA / CSR 상황에서 페이지 이동(라우팅)이 일어날 때는 다음과 같이 동작한다 (+브라우저 라우터 기준이다).
URL의 변경과 라우팅은 이뤄지지만 모든 것이 클라이언트 사이드에서 행해지고 서버는 아무런 관계가 없다.
위와 같은 방식의 Browser Router를 이용한 라우팅은 해당 사이트를 사용하는 모든 유저가 무조건 홈페이지(인덱스 페이지 /
)로 처음 접속하여 버튼을 눌러서만 이동 한다면, 문제 될 것이 없다. 인덱스 페이지에 접속하는 순간, URL의 요청을 받은 서버는 필요한 자원(Html, CSS, JS)을 제공할 것이고 그 다음 라우팅은 앞서 말한 CSR의 방식으로 동작할 것이기 때문이다. 하지만 유저가 언제나 이렇게 행동할 것이라고 누구도 장담 할 수 없다. 누군가는 F5를 눌러 의도적인 새로 고침을 유도할 것이고, 누군가는 인덱스 페이지가 아닌 다른 페이지(ex. /about
) 주소를 주소창에 직접 입력하여 바로 접근하고 싶어할 것이다.
그럼 유저가 인덱스 페이지가 아닌 페이지에서 의도적으로 새로 고침을 하거나, 주소를 직접 쳐서 들어오려 되면 어떻게 될까?
www.example.com/detail
페이지에서 새로 고침을 시도한다.💡 바로 이 부분이 Browser Router를 이용하면, 새로 고침시에 에러가 난다! 는 것이다.
이를 해결하는 방법은 크게 2가지 이다.
www.domain.com/#/path
과 같은 형태로 이루어지는데, URL의 해시 부분은 서버에 전송되지 않고 브라우저에서만 사용된다.www.domain.com
(인덱스 페이지)에 대한 요청만 받아 들이게 되므로 무엇을 반환해야 하는지 알고 있다./
이외의 path로 서버에 요청할 때 무조건 서버가 무조건 index.html을 리턴하도록 설정해준다. 이 방법이 글 초반에 언급한 서버의 추가적인 세팅
이다.
브라우저 라우터와 해시 라우터의 근본적인 동작 원리를 알아보고 나니, 왜 어드민에 해시 라우터를 사용했는지 이해되었다. 사내에서만 사용하는 작은 서비스이고 SEO를 고려할 필요도 없기 때문에 따로 추가적인 세팅을 하며 웹서버를 구축하기 보다는 간편하게 해시 라우터를 사용하여 새로 고침 에러를 방지한 것이었다. 사실 이제서야 이런 부분에 대해 이해하게 되었다는 것이 조금 부끄럽기도 하다. 익숙하고 자연스럽다고 생각한 것들에 좀 더 ‘왜’라는 물음표를 자주 띄워야 겠다는 생각이 든다.