SPA 404 이슈 해결

2024-07-19 · 2 min read

개요

이 글은 실무에서 정적 사이트 배포 환경을 구성하면서 겪은 SPA 관련 404 오류 이슈에 대한 해결 과정을 다룹니다.

SPA란?

SPA(Single-page application)란 단일 HTML 문서로 이루어진 웹사이트를 의미합니다. 기존의 여러 HTML 파일을 사용하던 방식과 달리, SPA는 하나의 HTML 파일을 사용하며 모든 콘텐츠는 JavaScript를 통해 동적으로 생성됩니다.

Angular를 시작으로 React, Vue 등 다양한 SPA 프레임워크가 등장하며 프론트엔드 개발의 주류로 자리 잡았습니다. SPA는 클라이언트 사이드 라우팅을 통해 페이지 이동을 구현하며, 페이지를 새로 로드하지 않고도 화면을 전환할 수 있어 사용자에게 더욱 쾌적한 경험을 제공합니다.

클라이언트 사이드 라우팅이란?

클라이언트 사이드 라우팅은 SPA에서 사용자가 링크를 클릭할 때 페이지를 새로고침하지 않고도 다른 페이지로 이동할 수 있도록 하는 방식입니다. 주요 기능은 다음과 같습니다.

  • URL 변경을 감지해 그 경로에 매핑된 컴포넌트를 렌더링합니다.

  • 새로고침 없이 사용자의 URL을 임의로 조작합니다.

이 URL 변경 방식은 크게 두 가지로 나뉩니다.

  1. window.history API를 사용:

    window.history API의 pushState, replaceState 등의 메서드를 사용하여 새로고침을 발생시키지 않고 URL을 변경하는 방식입니다. Svelte의 svelte-routing 라이브러리가 여기에 해당합니다.

    URL의 실제 경로를 변경하므로 정적 사이트로 배포할 경우, 후술할 404 오류 이슈를 유발합니다.

  2. hash property를 사용:

    URL의 hash property를 사용하는 방식으로 Svelte의 svelte-spa-router 라이브러리가 여기에 해당합니다.

    # 뒤에 붙는 서버로는 전송되지 않기 때문에 서버는 이를 인식하지 않고, 항상 동일한 HTML 파일을 반환합니다. 이러한 특성을 이용해 라우팅하는 방식으로, SEO에는 불리한 면이 있습니다.

저는 원래 2번 방식 기반의 라이브러리를 사용했기 때문에 큰 문제가 없었지만, 모종의 이유로 1번 방식으로 교체하면서 이슈를 겪게 되었습니다.

SPA routing 404 오류 이슈

본디 URL이란 사용자가 원하는 리소스를 요청하기 위한 경로를 의미합니다. 즉, https://foo.bar/baz라는 주소로 요청을 한다면, 서버는 기본적으로 ./baz.html 파일을 찾아서 응답으로 전송합니다.

그러나 SPA는 단일 HTML 파일(./index.html)만이 존재하기 때문에, 다른 경로로 이동한 상태에서 새로고침 등으로 새 문서 로드를 유발하면 404 오류가 발생합니다. 그 경로에 해당하는 HTML이 존재하지 않기 때문입니다.

한편 해시 라우팅을 사용한다면 이 문제는 발생하지 않습니다. 예를 들어, https://foo.bar/#/baz라는 URL에서 #/baz는 Hash property이므로 서버는 이를 인식하지 못합니다. 따라서 서버는 ./index.html을 응답으로 보내게 됩니다.

어쨌든 이 문제를 해결하기 위해서는 어떤 페이지를 요청하든 항상 ./index.html을 반환하도록 처리해야 합니다.

AWS S3, CloudFront에서 오류 페이지 핸들링

저는 AWS S3와 CloudFront로 배포 환경을 구성했기 때문에 여기서 핸들링을 할 필요가 있었습니다. S3와 CloudFront 둘 다 오류 처리 기능을 제공하기 때문에, 둘 중 하나를 선택할 수 있었습니다.

S3에서 오류 처리

s3-static-site-hosting.png

S3의 정적 웹 사이트 호스팅(Static website hosting) 기능을 사용하면 오류 시 보여줄 문서를 설정할 수 있습니다.

  • 장점:

    • 간편하게 설정 가능

    • S3의 기본 기능을 사용하므로 추가적인 비용이 발생하지 않음

  • 단점:

    • 세부적인 오류 처리 설정이 어려움

    • 어디까지나 오류가 발생했을 때 응답으로 전송할 문서를 설정하는 것이기 때문에, 네트워크 상에서 여전히 오류로 간주되어 SEO에 불리할 수 있음

CloudFront에서 오류 처리

cloudfront-custom-error-response.png

CloudFront의 사용자 정의 오류 응답(Custom error response) 을 사용하면 에러 코드별로 어떻게 처리할지 세세하게 설정할 수 있습니다.

  • 장점:

    • 오류 코드별로 세세한 설정을 할 수 있어 유연성이 높음

    • 캐싱 기능을 통해 성능을 높일 수 있음

  • 단점:

    • CloudFront 사용에 따른 추가 비용이 발생할 수 있음

어느 방법을 사용하든 SPA는 정상적으로 동작하지만, SEO 친화적인 처리를 위해 저는 CloudFront에서 오류를 처리하는 방식을 선택했습니다.

결론

저는 프론트엔드 개발을 Next.js로 시작했기 때문에, SPA나 CSR에 대해서는 이론적으로만 공부했을 뿐 실제로 배포까지 진행해본 적은 없었습니다. 그렇기에 이번에 겪은 문제는 다소 생소했습니다.

아마도 아직 SSR 프레임워크가 널리 사용되기 전에는 꽤 일반적인 문제였을 것입니다. Next.js와 같은 SSR 프레임워크가 보편화되면서 서버 로직과 인프라에 대한 고민을 덜 하게 되었지만, 이번 경험을 통해 프론트엔드 개발자라도 인프라와 배포 과정에 대한 이해가 중요함을 다시금 깨달았습니다.

Copyright 2022-2024.hanse-kimAll right reserved.