최근 React-Router를 활용하여 깃허브페이지나 AWS로 배포를 할 때 겪었던 문제에 대해 호기심이 생겨 알아보았고, 이유를 알게되었다.
😡 문제발생
localhost에서 React-Router를 활용하여 특정 뷰에 Path를 적용시켜주었을 때에는 새로고침을 해도 뷰가 잘 구성이 된다.
깃허브페이지나 AWS를 통한 배포(이하 배포로 통일하겠음)를 하였을 때에는, 404에러를 반환한다.
🧐 왤까?
원인은 React 자체의 특성에 있었다.(알고있던 특징이였는데 전혀 예상을 못했다;)
React는 CSR
React는 기본적으로 클라이언트 사이드 렌더링이다. React-Router로 path이동을 시키는것처럼 보여지지만, 그냥 이름만 지어줄 뿐 그 사실이 변하지 않는다.
사용자가 최초 접속 이후 서버에 요청을 하면, build된 index.html파일을 보내준다.
그 html파일에는 번들링된 js나 css파일이 연결되어있는 상태이다.
html파일이 읽히면서, js와 css 파일이 작동이 된 이후, React-Router가 작동되는 형식이다. 즉, path이동과 routing은 작동을 하지만 모든것이 클라이언트 사이드에서 이뤄지고 서버는 아무런 관계가 없다.
만약, 이 상태에서 클라이언트 사이드에서 Routing이 이뤄지고, 새로고침을 하면 클라이언트에서 서버에 새롭게 파일을 요청하게 되는데, 이미 url은 React-Router의 path로 얼룩져 있는 상태이기 때문에, 서버는 그것이 무엇을 반환해달라는 말인지 알 지 못한다. 따라서 404 Not Found 에러를 반환하는것이다. 당연히, 아무런 path가 없는 첫 화면은 ’/’ 상태이기 때문에 index.html을 잘 받아와 에러가 생기지 않는 것이다.
😄 해결방법
HashRouter
가장 쉬운 방법으로는 BrowserRouter -> HashRouter 변경하는것이다.
서버가 해당 요청 url을 읽을 때, # 뒤로는 인식(?)하지 못한다고 한다. 따라서 / 만 읽고, index.html을 잘 받아오는것이다.
근데 중요한점은 HashRouter를 쓰면 url앞에 /#/가 들어가게되는데 이게 너무 싫다.
index.html 리다이렉션 - 깃허브
깃허브페이지는 서버에서 404에러를 반환했을 때, 깃허브에서 기본적으로 제공하는 404.html파일을 출력시키도록 되어있다.
따라서 우리는 build될 때, 직접 만든 404.html파일또한 포함되게 하면 되는데, 해당 html은 즉시실행 메소드로 현재의 url에서 router로 인해 생성된 path 앞에 서버가 읽지 못하는 /?/를 포함시켜 window.location.replace로 해당 주소로 이동시킨다.
당연히 서버는 ? 이후는 읽지 못하고 앞의 깃허브페이지 메인 주소만 읽고 index.html을 반환하고, 반환되는 index.html파일에서 ? 등의 불필요한 부분을 지워주는 메소드가 가장 먼저 실행되도록 한다(main script가 읽히기 전). 그 이후로 js파일의 React-Router가 작동되어 원하는 화면을 볼 수 있게된다.