증상

 

404 Not Found

Vue.js를 사용한 웹 애플리케이션 개발 중 새로고침 시 404 페이지로 리다이렉트 되는 이슈가 발생하였다.

 

원인

 

해당 이슈는 SPA 앱을 개발할 때 발생하는 이슈로 connect-history-api-fallback 현상이라 한다.

Vue.js의 경우 라우터에 등록된 Vue 컴퍼넌트들을 모듈 번들러를 통하여 Javascript로 컴파일하여 WebServer의 Document Root 폴더에 가지고 있다. 

라우터를 이용한 정상적인 페이지 요청 시에는 해당 페이지에 맞는 js 파일을 클라이언트가 요청하지만, 새로고침 시에는 도메인과 라우터 Path를 가지고 WebServer에 존재하지 않는 요청을 보내기 때문에 발생하는 이슈이다.

 

해결방법

라이브러리를 사용하는 방법도 있지만, 공식 문서에 나와있는 서버 설정방법을 사용하여 해결하였다.

https://router.vuejs.org/guide/essentials/history-mode.html

 

Different History modes | Vue Router

Different History modes The history option when creating the router instance allows us to choose among different history modes. Hash Mode The hash history mode is created with createWebHashHistory(): import { createRouter, createWebHashHistory } from 'vue-

router.vuejs.org

 

해당 방법은 WebServer에 Http 요청이 들어왔을 때, 해당 요청을 rewrite 하는 방법이다.

 

<IfModule mod_rewrite.c>
  RewriteEngine On
  RewriteBase /
  RewriteRule ^index\.html$ - [L]
  RewriteCond %{REQUEST_FILENAME} !-f
  RewriteCond %{REQUEST_FILENAME} !-d
  RewriteRule . /index.html [L]
</IfModule>

 

서버 설정 문법은 아파치 레퍼런스 문서를 참고하면 된다.

https://httpd.apache.org/docs/current/rewrite/flags.html

 

RewriteRule Flags - Apache HTTP Server Version 2.4

RewriteRule Flags This document discusses the flags which are available to the RewriteRule directive, providing detailed explanations and examples. A RewriteRule can have its behavior modified by one or more flags. Flags are included in square brackets at

httpd.apache.org

위 설정문을 예시로 번역하면

RewriteRule ^index\.html$ - [L]

^index\.html$ 는 정규표현식으로 

index로 시작하며(^ 접두사)  (특수문자 .) html 로 끝나지 않는($ 접미사) 요청들이 다시 쓰는 대상이며

[L] 플래그는 조건의 끝을 의미한다.

Rewirte Cond 문장의 ! -f, ! -d는 파일과 디렉토리를 의미한다.

 

결론적으로 SPA 애플리케이션의 초기진입 페이지인 index.html이 아닌 URL로 들어오는 요청들을 index.html로 다시 보내는 설정이다.

위와같은 설정을 웹서버에 적용하여, Vue.js의 새로고침 시 404 페이지 리다이렉트 이슈를 해결할 수 있다.

 

참고자료

 

https://stackoverflow.com/questions/36399319/vue-router-return-404-when-revisit-to-the-url

 

Vue Router return 404 when revisit to the url

I just enable Vue router history mode. And it work fine when I visit to vue routing via v-href or href. But, when I try to refresh that page or go directly from browser address bar, it just return ...

stackoverflow.com

 

 

 

 

개요

Vue.js

Vue.js는 JavaScript 프레임워크입니다. 

표준 HTML, CSS, JavaScript로 만들어져 있으며, 선언적이고 컴포넌트 기반의 프로그래밍 모델을 제공하여 효율적으로 사용자 인터페이스를 개발할 수 있도록 도와줍니다.

Vue의 가장 큰 특징 두가지는 선언적 렌더링(Declarative Rendering)과 반응성(Reactivity)입니다.

 

 

선언적 렌더링(Declarative Rendering)

Vue는 표준 HTML을 템플릿 문법과 함께 확장하여 Javascript 상태에 기반한 HTML 결과물을 만들어냅니다.

<div id="app">
  {{ message }}
</div>
var app = new Vue({
  el: '#app',
  data: {
    message: '안녕하세요 Vue!'
  }
})

 

반응성(Reactivity)

Vue는 JavaScript의 상태변화를 추적하고, 변화가 발생하였을 때 DOM을 효과적으로 업데이트 할 수 있습니다.

<div id="app-2">
  <span v-bind:title="message">
    내 위에 잠시 마우스를 올리면 동적으로 바인딩 된 title을 볼 수 있습니다!
  </span>
</div>
var app2 = new Vue({
  el: '#app-2',
  data: {
    message: '이 페이지는 ' + new Date() + ' 에 로드 되었습니다'
  }
})

 

 

진보적인 프레임워크

Vue는 프론트엔드 개발에 필요한 공통적인 특징들을 지원하는 프레임워크이며 생태계입니다.

Vue는 유연하고 점진적으로 채택할 수 있도록 설계되었습니다.

사용 사례에 따라 Vue를 다양한 방식으로 사용할 수 있습니다.

  • 빌드 단계 없이 정적 HTML 향상 모든 페이지에 웹 구성 요소로 포함
  • 단일 페이지 애플리케이션(SPA)
  • 풀스택/서버 측 렌더링(SSR)
  • Jamstack/정적 사이트 생성(SSG)
  • 데스크탑, 모바일, WebGL, 터미널까지 타겟팅

 

 

싱글 파일 컴포넌트

Vue 프로젝트에서 단일 파일 구성 요소(*.vue 파일이라고도 함, SFC로 약칭)라는 HTML과 유사한 파일 형식을 사용하여 Vue 구성 요소의 논리(JavaScript), 템플릿(HTML) 및 스타일(CSS)을 하나의 파일로 캡슐화합니다.

 

<script>
export default {
  data() {
    return {
      count: 0
    }
  }
}
</script>

<template>
  <button @click="count++">Count is: {{ count }}</button>
</template>

<style scoped>
button {
  font-weight: bold;
}
</style>

 

 

API 스타일

Vue 구성 요소는 옵션 API와 구성 API의 두 가지 API 스타일로 작성할 수 있습니다.

 

Options API

Options API를 사용하여 데이터, 메소드, 마운트와 같은 옵션의 개체를 사용하여 구성 요소의 논리를 정의합니다. 옵션으로 정의된 속성은 구성 요소 인스턴스를 가리키는 내부 함수에 노출됩니다.

<script>
export default {
  // Properties returned from data() become reactive state
  // and will be exposed on `this`.
  data() {
    return {
      count: 0
    }
  },

  // Methods are functions that mutate state and trigger updates.
  // They can be bound as event listeners in templates.
  methods: {
    increment() {
      this.count++
    }
  },

  // Lifecycle hooks are called at different stages
  // of a component's lifecycle.
  // This function will be called when the component is mounted.
  mounted() {
    console.log(`The initial count is ${this.count}.`)
  }
}
</script>

<template>
  <button @click="increment">Count is: {{ count }}</button>
</template>

 

Composition API

구성 API를 사용하면 가져온 API 기능을 사용하여 구성 요소의 논리를 정의할 수 있습니다. SFC에서는 일반적으로 <script setup>과 함께 Composition API를 사용합니다. setup 속성은 더 적은 상용구로 컴포지션 API를 사용할 수 있도록 하는 컴파일 타임 변환을 수행하도록 Vue에 지시하는 힌트입니다. 예를 들어 <script setup>에서 선언된 import와 최상위 변수/함수는 템플릿에서 직접 사용할 수 있습니다.

다음은 정확히 동일한 템플릿을 사용하지만 대신 Composition API와 <script setup>을 사용하는 동일한 구성 요소입니다.

<script setup>
import { ref, onMounted } from 'vue'

// reactive state
const count = ref(0)

// functions that mutate state and trigger updates
function increment() {
  count.value++
}

// lifecycle hooks
onMounted(() => {
  console.log(`The initial count is ${count.value}.`)
})
</script>

<template>
  <button @click="increment">Count is: {{ count }}</button>
</template>

 

 

참고

Vue.js 레퍼런스 문서https://vuejs.org/guide/introduction.html#the-progressive-framework

 

 
 
 

+ Recent posts