refactor: gamedata 없을 때 error 페이지 노출 수정, 다국어 파일 경로 수정
This commit is contained in:
@@ -67,7 +67,21 @@ interface ErrorProps {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const { tm } = useI18n()
|
// Configuration
|
||||||
|
const runtimeConfig = useRuntimeConfig()
|
||||||
|
const dataResourcesUrl = runtimeConfig.public.dataResourcesUrl as string
|
||||||
|
const multilingualFileName = 'STOVE_PUBTEMPLATE_common_error-message.json'
|
||||||
|
|
||||||
|
// Multilingual
|
||||||
|
const resultGetMultilingual = await useGetMultilingual({
|
||||||
|
baseApiUrl: dataResourcesUrl,
|
||||||
|
fileName: multilingualFileName,
|
||||||
|
})
|
||||||
|
const { tm }: any = useI18n({
|
||||||
|
useScope: 'local',
|
||||||
|
messages: Object(resultGetMultilingual?.value?.multilingual),
|
||||||
|
})
|
||||||
|
|
||||||
const props = withDefaults(defineProps<ErrorProps>(), {
|
const props = withDefaults(defineProps<ErrorProps>(), {
|
||||||
error: () => ({}),
|
error: () => ({}),
|
||||||
})
|
})
|
||||||
@@ -107,6 +121,7 @@ const handleKeydown = (e: KeyboardEvent) => {
|
|||||||
// 500 에러 발생 시 /error 페이지로 리다이렉트
|
// 500 에러 발생 시 /error 페이지로 리다이렉트
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
const statusCode = currentError.value?.statusCode
|
const statusCode = currentError.value?.statusCode
|
||||||
|
console.log("🚀 ~ statusCode:", nuxtError)
|
||||||
|
|
||||||
if (statusCode === 500) {
|
if (statusCode === 500) {
|
||||||
errorTitle.value = tm('Error_500_Inconvenience')
|
errorTitle.value = tm('Error_500_Inconvenience')
|
||||||
|
|||||||
135
error.vue
135
error.vue
@@ -3,49 +3,61 @@
|
|||||||
<LayoutsStoveHeader />
|
<LayoutsStoveHeader />
|
||||||
|
|
||||||
<Transition name="fade">
|
<Transition name="fade">
|
||||||
<div v-if="!isLoading" class="flex-1 flex items-center justify-center p-25">
|
<div
|
||||||
|
v-if="!isLoading"
|
||||||
|
class="flex-1 flex items-center justify-center p-25"
|
||||||
|
>
|
||||||
<div class="flex flex-col items-center gap-6 w-full">
|
<div class="flex flex-col items-center gap-6 w-full">
|
||||||
<!-- Stove Logo -->
|
<!-- Stove Logo -->
|
||||||
<div class="flex items-center justify-center h-7">
|
<div class="flex items-center justify-center h-7">
|
||||||
<img
|
<img
|
||||||
src="/images/common/logo-stove.svg"
|
src="/images/common/logo-stove.svg"
|
||||||
alt="Stove"
|
alt="Stove"
|
||||||
class="h-full w-auto"
|
class="h-full w-auto"
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Error Icon and Text -->
|
|
||||||
<div class="flex flex-col items-center gap-4 w-full">
|
|
||||||
<!-- Error Icon -->
|
|
||||||
<div class="flex items-center justify-center">
|
|
||||||
<img
|
|
||||||
src="/images/common/img_error.png"
|
|
||||||
alt="Error"
|
|
||||||
class="w-40 h-40 md:w-60 md:h-60"
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Error Text -->
|
<!-- Error Icon and Text -->
|
||||||
<div class="flex flex-col items-center gap-2 w-full">
|
<div class="flex flex-col items-center gap-4 w-full">
|
||||||
<h1 class="font-medium text-xl md:text-2xl leading-[1.5] tracking-[-0.03em] text-center text-[#1F1F1F] m-0">
|
<!-- Error Icon -->
|
||||||
<span v-dompurify-html="errorTitle"></span>
|
<div class="flex items-center justify-center">
|
||||||
</h1>
|
<img
|
||||||
<p v-dompurify-html="errorMsg" class="font-normal text-sm md:text-base leading-[1.7] md:leading-[1.625] tracking-[-0.03em] text-center text-[#666666] m-0"></p>
|
src="/images/common/img_error.png"
|
||||||
</div>
|
alt="Error"
|
||||||
</div>
|
class="w-40 h-40 md:w-60 md:h-60"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- Home Button -->
|
<!-- Error Text -->
|
||||||
<AtomsButton class="flex items-center justify-center font-medium text-sm leading-[1.4] tracking-[-0.03em] text-white bg-[#FC4420] border border-black/10 rounded-lg px-10 h-12 cursor-pointer transition-all duration-300 backdrop-blur-[30px] shadow-[0px_0.9131946563720703px_1.4666459560394287px_0px_rgba(0,0,0,0.06),0px_2.194533586502075px_3.5245540142059326px_0px_rgba(0,0,0,0.09)] hover:bg-[#E03D1C] hover:shadow-[0px_0.9131946563720703px_1.4666459560394287px_0px_rgba(0,0,0,0.06),0px_2.194533586502075px_3.5245540142059326px_0px_rgba(0,0,0,0.09),0px_4.1321120262146px_6.636422634124756px_0px_rgba(0,0,0,0.12)] active:translate-y-px" @click="handleError">
|
<div class="flex flex-col items-center gap-2 w-full">
|
||||||
<span v-dompurify-html="tm('Error_Official_Page')"></span>
|
<h1
|
||||||
</AtomsButton>
|
class="font-medium text-xl md:text-2xl leading-[1.5] tracking-[-0.03em] text-center text-[#1F1F1F] m-0"
|
||||||
|
>
|
||||||
|
<span v-dompurify-html="errorTitle"></span>
|
||||||
|
</h1>
|
||||||
|
<p
|
||||||
|
v-dompurify-html="errorMsg"
|
||||||
|
class="font-normal text-sm md:text-base leading-[1.7] md:leading-[1.625] tracking-[-0.03em] text-center text-[#666666] m-0"
|
||||||
|
></p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Home Button -->
|
||||||
|
<AtomsButton
|
||||||
|
type="action"
|
||||||
|
button-size="size-small md:size-large"
|
||||||
|
background-color="#FC4420"
|
||||||
|
text-color="#FFFFFF"
|
||||||
|
@click="handleError"
|
||||||
|
>
|
||||||
|
<span v-dompurify-html="tm('Error_Official_Page')"></span>
|
||||||
|
</AtomsButton>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Transition>
|
</Transition>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
interface ErrorProps {
|
interface ErrorProps {
|
||||||
error?: {
|
error?: {
|
||||||
@@ -55,9 +67,23 @@ interface ErrorProps {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const { tm } = useI18n()
|
// Configuration
|
||||||
|
const runtimeConfig = useRuntimeConfig()
|
||||||
|
const dataResourcesUrl = runtimeConfig.public.dataResourcesUrl as string
|
||||||
|
const multilingualFileName = 'STOVE_PUBTEMPLATE_common_error-message.json'
|
||||||
|
|
||||||
|
// Multilingual
|
||||||
|
const resultGetMultilingual = await useGetMultilingual({
|
||||||
|
baseApiUrl: dataResourcesUrl,
|
||||||
|
fileName: multilingualFileName,
|
||||||
|
})
|
||||||
|
const { tm }: any = useI18n({
|
||||||
|
useScope: 'local',
|
||||||
|
messages: Object(resultGetMultilingual?.value?.multilingual),
|
||||||
|
})
|
||||||
|
|
||||||
const props = withDefaults(defineProps<ErrorProps>(), {
|
const props = withDefaults(defineProps<ErrorProps>(), {
|
||||||
error: () => ({})
|
error: () => ({}),
|
||||||
})
|
})
|
||||||
const nuxtError = useError()
|
const nuxtError = useError()
|
||||||
const currentError = computed(() => props.error || nuxtError.value)
|
const currentError = computed(() => props.error || nuxtError.value)
|
||||||
@@ -67,17 +93,34 @@ const isLoading = ref(true)
|
|||||||
const errorTitle = ref('')
|
const errorTitle = ref('')
|
||||||
const errorMsg = ref('')
|
const errorMsg = ref('')
|
||||||
|
|
||||||
//error clear 함수 생성
|
//error clear 함수 생성
|
||||||
|
const localePath = useLocalePath()
|
||||||
const handleError = () => clearError({ redirect: '/' })
|
|
||||||
|
|
||||||
|
|
||||||
|
// const handleError = () => clearError({ redirect: '/' })
|
||||||
|
const handleError = () => {
|
||||||
|
window.location.href = localePath('/')
|
||||||
|
}
|
||||||
|
const handleBack = () => {
|
||||||
|
// 에러 상태를 클리어하고 이전 페이지로 이동
|
||||||
|
// popstate 이벤트가 이미 발생한 경우이므로 추가 동작 불필요
|
||||||
|
// 키보드 백스페이스의 경우에만 명시적으로 뒤로가기 실행
|
||||||
|
window.location.href = localePath('/')
|
||||||
|
// navigateTo(`${router.currentRoute.value.path}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 백스페이스 키 처리
|
||||||
|
const handleKeydown = (e: KeyboardEvent) => {
|
||||||
|
if (
|
||||||
|
e.key === 'Backspace' &&
|
||||||
|
!['INPUT', 'TEXTAREA'].includes((e.target as HTMLElement).tagName)
|
||||||
|
) {
|
||||||
|
e.preventDefault()
|
||||||
|
handleBack()
|
||||||
|
}
|
||||||
|
}
|
||||||
// 500 에러 발생 시 /error 페이지로 리다이렉트
|
// 500 에러 발생 시 /error 페이지로 리다이렉트
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
const statusCode = currentError.value?.statusCode
|
const statusCode = currentError.value?.statusCode
|
||||||
console.log("🚀 ~ 1111currentError==:", currentError.value?.message)
|
|
||||||
console.log("🚀 ~ 1111statusCode:", statusCode)
|
|
||||||
|
|
||||||
if (statusCode === 500) {
|
if (statusCode === 500) {
|
||||||
errorTitle.value = tm('Error_500_Inconvenience')
|
errorTitle.value = tm('Error_500_Inconvenience')
|
||||||
@@ -86,10 +129,16 @@ onMounted(() => {
|
|||||||
errorTitle.value = tm('Error_404_Not_Found')
|
errorTitle.value = tm('Error_404_Not_Found')
|
||||||
errorMsg.value = tm('Error_404_Not_Found2')
|
errorMsg.value = tm('Error_404_Not_Found2')
|
||||||
}
|
}
|
||||||
|
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
isLoading.value = false
|
isLoading.value = false
|
||||||
})
|
})
|
||||||
})
|
|
||||||
|
|
||||||
</script>
|
window.addEventListener('keydown', handleKeydown)
|
||||||
|
window.addEventListener('popstate', handleBack)
|
||||||
|
})
|
||||||
|
onUnmounted(() => {
|
||||||
|
window.removeEventListener('keydown', handleKeydown)
|
||||||
|
window.removeEventListener('popstate', handleBack)
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import fallback from './fallback/de'
|
|||||||
export default defineI18nLocale(async (locale: string) => {
|
export default defineI18nLocale(async (locale: string) => {
|
||||||
const runtimeConfig = useRuntimeConfig()
|
const runtimeConfig = useRuntimeConfig()
|
||||||
const dataResourcesUrl = runtimeConfig.public.dataResourcesUrl as string
|
const dataResourcesUrl = runtimeConfig.public.dataResourcesUrl as string
|
||||||
const multilingualFileName = 'STOVE_PUBTEMPLATE_homepage_brand_secure.json'
|
const multilingualFileName = 'STOVE_PUBTEMPLATE_common_translations.json'
|
||||||
try {
|
try {
|
||||||
const resultGetMultilingual = await useGetMultilingual({
|
const resultGetMultilingual = await useGetMultilingual({
|
||||||
baseApiUrl: dataResourcesUrl,
|
baseApiUrl: dataResourcesUrl,
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import fallback from './fallback/en'
|
|||||||
export default defineI18nLocale(async (locale: string) => {
|
export default defineI18nLocale(async (locale: string) => {
|
||||||
const runtimeConfig = useRuntimeConfig()
|
const runtimeConfig = useRuntimeConfig()
|
||||||
const dataResourcesUrl = runtimeConfig.public.dataResourcesUrl as string
|
const dataResourcesUrl = runtimeConfig.public.dataResourcesUrl as string
|
||||||
const multilingualFileName = 'STOVE_PUBTEMPLATE_homepage_brand_secure.json'
|
const multilingualFileName = 'STOVE_PUBTEMPLATE_common_translations.json'
|
||||||
try {
|
try {
|
||||||
const resultGetMultilingual = await useGetMultilingual({
|
const resultGetMultilingual = await useGetMultilingual({
|
||||||
baseApiUrl: dataResourcesUrl,
|
baseApiUrl: dataResourcesUrl,
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import fallback from './fallback/es'
|
|||||||
export default defineI18nLocale(async (locale: string) => {
|
export default defineI18nLocale(async (locale: string) => {
|
||||||
const runtimeConfig = useRuntimeConfig()
|
const runtimeConfig = useRuntimeConfig()
|
||||||
const dataResourcesUrl = runtimeConfig.public.dataResourcesUrl as string
|
const dataResourcesUrl = runtimeConfig.public.dataResourcesUrl as string
|
||||||
const multilingualFileName = 'STOVE_PUBTEMPLATE_homepage_brand_secure.json'
|
const multilingualFileName = 'STOVE_PUBTEMPLATE_common_translations.json'
|
||||||
try {
|
try {
|
||||||
const resultGetMultilingual = await useGetMultilingual({
|
const resultGetMultilingual = await useGetMultilingual({
|
||||||
baseApiUrl: dataResourcesUrl,
|
baseApiUrl: dataResourcesUrl,
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import fallback from './fallback/fr'
|
|||||||
export default defineI18nLocale(async (locale: string) => {
|
export default defineI18nLocale(async (locale: string) => {
|
||||||
const runtimeConfig = useRuntimeConfig()
|
const runtimeConfig = useRuntimeConfig()
|
||||||
const dataResourcesUrl = runtimeConfig.public.dataResourcesUrl as string
|
const dataResourcesUrl = runtimeConfig.public.dataResourcesUrl as string
|
||||||
const multilingualFileName = 'STOVE_PUBTEMPLATE_homepage_brand_secure.json'
|
const multilingualFileName = 'STOVE_PUBTEMPLATE_common_translations.json'
|
||||||
try {
|
try {
|
||||||
const resultGetMultilingual = await useGetMultilingual({
|
const resultGetMultilingual = await useGetMultilingual({
|
||||||
baseApiUrl: dataResourcesUrl,
|
baseApiUrl: dataResourcesUrl,
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import fallback from './fallback/ja'
|
|||||||
export default defineI18nLocale(async (locale: string) => {
|
export default defineI18nLocale(async (locale: string) => {
|
||||||
const runtimeConfig = useRuntimeConfig()
|
const runtimeConfig = useRuntimeConfig()
|
||||||
const dataResourcesUrl = runtimeConfig.public.dataResourcesUrl as string
|
const dataResourcesUrl = runtimeConfig.public.dataResourcesUrl as string
|
||||||
const multilingualFileName = 'STOVE_PUBTEMPLATE_homepage_brand_secure.json'
|
const multilingualFileName = 'STOVE_PUBTEMPLATE_common_translations.json'
|
||||||
try {
|
try {
|
||||||
const resultGetMultilingual = await useGetMultilingual({
|
const resultGetMultilingual = await useGetMultilingual({
|
||||||
baseApiUrl: dataResourcesUrl,
|
baseApiUrl: dataResourcesUrl,
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import fallback from './fallback/ko'
|
|||||||
export default defineI18nLocale(async (locale: string) => {
|
export default defineI18nLocale(async (locale: string) => {
|
||||||
const runtimeConfig = useRuntimeConfig()
|
const runtimeConfig = useRuntimeConfig()
|
||||||
const dataResourcesUrl = runtimeConfig.public.dataResourcesUrl as string
|
const dataResourcesUrl = runtimeConfig.public.dataResourcesUrl as string
|
||||||
const multilingualFileName = 'STOVE_PUBTEMPLATE_homepage_brand_secure.json'
|
const multilingualFileName = 'STOVE_PUBTEMPLATE_common_translations.json'
|
||||||
try {
|
try {
|
||||||
const resultGetMultilingual = await useGetMultilingual({
|
const resultGetMultilingual = await useGetMultilingual({
|
||||||
baseApiUrl: dataResourcesUrl,
|
baseApiUrl: dataResourcesUrl,
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import fallback from './fallback/pt'
|
|||||||
export default defineI18nLocale(async (locale: string) => {
|
export default defineI18nLocale(async (locale: string) => {
|
||||||
const runtimeConfig = useRuntimeConfig()
|
const runtimeConfig = useRuntimeConfig()
|
||||||
const dataResourcesUrl = runtimeConfig.public.dataResourcesUrl as string
|
const dataResourcesUrl = runtimeConfig.public.dataResourcesUrl as string
|
||||||
const multilingualFileName = 'STOVE_PUBTEMPLATE_homepage_brand_secure.json'
|
const multilingualFileName = 'STOVE_PUBTEMPLATE_common_translations.json'
|
||||||
try {
|
try {
|
||||||
const resultGetMultilingual = await useGetMultilingual({
|
const resultGetMultilingual = await useGetMultilingual({
|
||||||
baseApiUrl: dataResourcesUrl,
|
baseApiUrl: dataResourcesUrl,
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import fallback from './fallback/th'
|
|||||||
export default defineI18nLocale(async (locale: string) => {
|
export default defineI18nLocale(async (locale: string) => {
|
||||||
const runtimeConfig = useRuntimeConfig()
|
const runtimeConfig = useRuntimeConfig()
|
||||||
const dataResourcesUrl = runtimeConfig.public.dataResourcesUrl as string
|
const dataResourcesUrl = runtimeConfig.public.dataResourcesUrl as string
|
||||||
const multilingualFileName = 'STOVE_PUBTEMPLATE_homepage_brand_secure.json'
|
const multilingualFileName = 'STOVE_PUBTEMPLATE_common_translations.json'
|
||||||
try {
|
try {
|
||||||
const resultGetMultilingual = await useGetMultilingual({
|
const resultGetMultilingual = await useGetMultilingual({
|
||||||
baseApiUrl: dataResourcesUrl,
|
baseApiUrl: dataResourcesUrl,
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import fallback from './fallback/zh-cn'
|
|||||||
export default defineI18nLocale(async (locale: string) => {
|
export default defineI18nLocale(async (locale: string) => {
|
||||||
const runtimeConfig = useRuntimeConfig()
|
const runtimeConfig = useRuntimeConfig()
|
||||||
const dataResourcesUrl = runtimeConfig.public.dataResourcesUrl as string
|
const dataResourcesUrl = runtimeConfig.public.dataResourcesUrl as string
|
||||||
const multilingualFileName = 'STOVE_PUBTEMPLATE_homepage_brand_secure.json'
|
const multilingualFileName = 'STOVE_PUBTEMPLATE_common_translations.json'
|
||||||
try {
|
try {
|
||||||
const resultGetMultilingual = await useGetMultilingual({
|
const resultGetMultilingual = await useGetMultilingual({
|
||||||
baseApiUrl: dataResourcesUrl,
|
baseApiUrl: dataResourcesUrl,
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import fallback from './fallback/zh-tw'
|
|||||||
export default defineI18nLocale(async (locale: string) => {
|
export default defineI18nLocale(async (locale: string) => {
|
||||||
const runtimeConfig = useRuntimeConfig()
|
const runtimeConfig = useRuntimeConfig()
|
||||||
const dataResourcesUrl = runtimeConfig.public.dataResourcesUrl as string
|
const dataResourcesUrl = runtimeConfig.public.dataResourcesUrl as string
|
||||||
const multilingualFileName = 'STOVE_PUBTEMPLATE_homepage_brand_secure.json'
|
const multilingualFileName = 'STOVE_PUBTEMPLATE_common_translations.json'
|
||||||
try {
|
try {
|
||||||
const resultGetMultilingual = await useGetMultilingual({
|
const resultGetMultilingual = await useGetMultilingual({
|
||||||
baseApiUrl: dataResourcesUrl,
|
baseApiUrl: dataResourcesUrl,
|
||||||
|
|||||||
@@ -59,6 +59,16 @@ export default defineNuxtRouteMiddleware(async (to, _from) => {
|
|||||||
to.path.includes('/error') ||
|
to.path.includes('/error') ||
|
||||||
to.path.includes('/inspection')
|
to.path.includes('/inspection')
|
||||||
) {
|
) {
|
||||||
|
console.log("🚀 ~ init.route.global error 페이지는 API 호출하지 않음")
|
||||||
|
showError(
|
||||||
|
createError({
|
||||||
|
statusCode: 500,
|
||||||
|
statusMessage:
|
||||||
|
'Internal Server Error',
|
||||||
|
fatal: false, // 즉시 에러 페이지로
|
||||||
|
data: { reason: 'post-not-found' },
|
||||||
|
})
|
||||||
|
)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ export default defineNuxtRouteMiddleware(async to => {
|
|||||||
|
|
||||||
// error 페이지는 API 호출하지 않음
|
// error 페이지는 API 호출하지 않음
|
||||||
if (pageUrl === '/error' || to.path.includes('/error')) {
|
if (pageUrl === '/error' || to.path.includes('/error')) {
|
||||||
|
console.log("🚀 ~ inspection error 페이지는 API 호출하지 않음")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -37,8 +38,6 @@ export default defineNuxtRouteMiddleware(async to => {
|
|||||||
baseApiUrl: stoveApiBaseUrl,
|
baseApiUrl: stoveApiBaseUrl,
|
||||||
gameId: stoveGameId,
|
gameId: stoveGameId,
|
||||||
})
|
})
|
||||||
console.log("🚀 ~ stoveApiBaseUrl:", stoveApiBaseUrl)
|
|
||||||
console.log("🚀 ~ stoveGameId:", stoveGameId)
|
|
||||||
|
|
||||||
// 게임 점검 -----
|
// 게임 점검 -----
|
||||||
// const { checkGameMaintenance } = useGetGameMaintenance()
|
// const { checkGameMaintenance } = useGetGameMaintenance()
|
||||||
|
|||||||
@@ -42,6 +42,7 @@ export default defineNuxtRouteMiddleware(async (to, _from) => {
|
|||||||
|
|
||||||
// error 페이지는 API 호출하지 않음
|
// error 페이지는 API 호출하지 않음
|
||||||
if (pageUrl === '/error' || to.path.includes('/error')) {
|
if (pageUrl === '/error' || to.path.includes('/error')) {
|
||||||
|
console.log("🚀 ~pageData.global error 페이지는 API 호출하지 않음")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// 페이지 이동 시 로딩 상태 시작
|
// 페이지 이동 시 로딩 상태 시작
|
||||||
|
|||||||
@@ -1,9 +1,17 @@
|
|||||||
import { LRUCache } from 'lru-cache'
|
import { LRUCache } from 'lru-cache'
|
||||||
import { getHeader, getRequestHost, defineEventHandler } from 'h3'
|
import {
|
||||||
|
getHeader,
|
||||||
|
getRequestHost,
|
||||||
|
defineEventHandler,
|
||||||
|
createError,
|
||||||
|
setCookie,
|
||||||
|
type H3Event,
|
||||||
|
} from 'h3'
|
||||||
import { ssrGetFinalLocale } from '../../utils/localeUtil'
|
import { ssrGetFinalLocale } from '../../utils/localeUtil'
|
||||||
import type { GameDataResponse } from '../../types/api/gameData'
|
import type { GameDataResponse } from '../../types/api/gameData'
|
||||||
import type { ResGetInspectionData } from '../../types/InspectionType'
|
import type { ResGetInspectionData, WebInspectionData } from '../../types/InspectionType'
|
||||||
import { isStaticFile } from '#layers/utils/commonUtil'
|
import { isStaticFile } from '#layers/utils/commonUtil'
|
||||||
|
import { getTrueClientIp } from '#layers/utils/apiUtil'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 캐시 제어 헤더를 설정하는 공통 함수
|
* 캐시 제어 헤더를 설정하는 공통 함수
|
||||||
@@ -68,7 +76,7 @@ const cache = new LRUCache({
|
|||||||
* @param baseDomain - 기본 도메인
|
* @param baseDomain - 기본 도메인
|
||||||
*/
|
*/
|
||||||
function setFinalLocaleCookie(
|
function setFinalLocaleCookie(
|
||||||
event: any,
|
event: H3Event,
|
||||||
finalLocale: string,
|
finalLocale: string,
|
||||||
baseDomain: string
|
baseDomain: string
|
||||||
) {
|
) {
|
||||||
@@ -85,7 +93,7 @@ function setFinalLocaleCookie(
|
|||||||
* @param event - 이벤트 객체
|
* @param event - 이벤트 객체
|
||||||
* @param finalLocale - 최종 언어
|
* @param finalLocale - 최종 언어
|
||||||
*/
|
*/
|
||||||
function fnLocaleMiddleware(event: any, finalLocale: string) {
|
function fnLocaleMiddleware(event: H3Event, finalLocale: string) {
|
||||||
// 이미 응답이 종료되었는지 확인
|
// 이미 응답이 종료되었는지 확인
|
||||||
if (event.node.res.headersSent || event.node.res.writableEnded) {
|
if (event.node.res.headersSent || event.node.res.writableEnded) {
|
||||||
return
|
return
|
||||||
@@ -133,43 +141,24 @@ export default defineEventHandler(async event => {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (event.path.includes('/error')) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// 이미 응답이 종료되었는지 확인 (리다이렉트 등으로 인한 중복 실행 방지)
|
// 이미 응답이 종료되었는지 확인 (리다이렉트 등으로 인한 중복 실행 방지)
|
||||||
if (event.node.res.headersSent || event.node.res.writableEnded) {
|
if (event.node.res.headersSent || event.node.res.writableEnded) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// const runType = `${config.public.runType}`
|
|
||||||
// console.log("🚀 ~ baseDomain:", config.public.baseDomain)
|
|
||||||
// const url = getRequestURL(event)
|
|
||||||
|
|
||||||
// if (['local', 'local-gate8', 'dev'].includes(runType)) {
|
|
||||||
// Sandbox 이상 환경에서만 동작 및 확인 가능 (local, dev는 통과 처리)
|
|
||||||
// try {
|
|
||||||
// 언어 코드 추출
|
|
||||||
// const finalLocale = ssrGetFinalLocale(event?.node.req.url, event.node.req.headers)
|
|
||||||
// console.log("🚀 ~ finalLocale:", finalLocale)
|
|
||||||
// setFinalLocaleCookie(event, finalLocale, baseDomain)
|
|
||||||
|
|
||||||
// -------------------------------------------------------------------------------
|
|
||||||
// [Locale Middleware]
|
|
||||||
// -------------------------------------------------------------------------------
|
|
||||||
// fnLocaleMiddleware(event, finalLocale)
|
|
||||||
// } catch (e) {
|
|
||||||
// console.error('[Exception] /server/middleware/middleware-02-global: ', e)
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
const runtimeConfig = useRuntimeConfig()
|
const runtimeConfig = useRuntimeConfig()
|
||||||
const iBaseApiUrl = `${runtimeConfig.public.stoveApiUrlServer}`
|
const iBaseApiUrl = runtimeConfig.public.stoveApiUrlServer
|
||||||
const baseDomain = `${runtimeConfig.public.baseDomain}`
|
const baseDomain = runtimeConfig.public.baseDomain
|
||||||
const stoveApiUrlBaseServer = runtimeConfig.public.stoveApiUrlServer
|
const apiUrl = `${iBaseApiUrl}/pub-comm/v1.0/template/game`
|
||||||
const apiUrl = `${stoveApiUrlBaseServer}/pub-comm/v1.0/template/game`
|
|
||||||
|
|
||||||
let initGameData: GameDataResponse | null = null
|
|
||||||
let initLangCodes: string[] | null = null
|
let initLangCodes: string[] | null = null
|
||||||
let finalLocale
|
let finalLocale: string
|
||||||
let cleanHost
|
let cleanHost: string | undefined
|
||||||
let initDefaultLocale
|
let initDefaultLocale: string | null = null
|
||||||
|
|
||||||
const host =
|
const host =
|
||||||
(getHeader(event, 'host') || getRequestHost(event)).toString() || ''
|
(getHeader(event, 'host') || getRequestHost(event)).toString() || ''
|
||||||
@@ -188,14 +177,13 @@ export default defineEventHandler(async event => {
|
|||||||
const initResponse = (await $fetch(apiUrl, {
|
const initResponse = (await $fetch(apiUrl, {
|
||||||
query: queryParams,
|
query: queryParams,
|
||||||
})) as GameDataResponse | null
|
})) as GameDataResponse | null
|
||||||
initGameData = initResponse || null
|
|
||||||
// console.log("🚀 ~ 00000 initGameData:", initGameData)
|
|
||||||
|
|
||||||
initLangCodes = initResponse?.value?.lang_codes || null
|
initLangCodes = initResponse?.value?.lang_codes || null
|
||||||
initDefaultLocale = initResponse?.value?.default_lang_code || null
|
initDefaultLocale = initResponse?.value?.default_lang_code || null
|
||||||
console.log('🚀 ~ initLangCodes:===========', initLangCodes)
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('init gameData load error:', error)
|
console.error('init gameData load error:', error)
|
||||||
|
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
const fullPath = event.path
|
const fullPath = event.path
|
||||||
@@ -247,28 +235,19 @@ export default defineEventHandler(async event => {
|
|||||||
initDefaultLocale
|
initDefaultLocale
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// 쿼리스트링에서 f 파라미터 값 추출
|
||||||
const path = event?.node.req.url || ''
|
const path = event?.node.req.url || ''
|
||||||
let queryStringF = ''
|
|
||||||
let fValue = ''
|
let fValue = ''
|
||||||
let test500 = false
|
|
||||||
if (path.includes('?')) {
|
if (path.includes('?')) {
|
||||||
queryStringF = path.split('?')[1]
|
|
||||||
// 쿼리스트링에서 f 파라미터 값 추출
|
|
||||||
try {
|
try {
|
||||||
const urlParams = new URLSearchParams(queryStringF)
|
const queryString = path.split('?')[1]
|
||||||
|
const urlParams = new URLSearchParams(queryString)
|
||||||
fValue = urlParams.get('f') || ''
|
fValue = urlParams.get('f') || ''
|
||||||
// 테스트용 500 에러 발생 (예: ?test500=true)
|
|
||||||
test500 = urlParams.get('test500') === 'true'
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error('쿼리스트링 파싱 에러:', e)
|
console.error('쿼리스트링 파싱 에러:', e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 테스트용 500 에러 발생
|
|
||||||
if (test500) {
|
|
||||||
throw new Error('테스트용 500 에러 발생')
|
|
||||||
}
|
|
||||||
|
|
||||||
// 미리보기 API 호출 처리
|
// 미리보기 API 호출 처리
|
||||||
if (fValue === 'preview') {
|
if (fValue === 'preview') {
|
||||||
cleanHost = 'samplegame.onstove.com'
|
cleanHost = 'samplegame.onstove.com'
|
||||||
@@ -278,7 +257,7 @@ export default defineEventHandler(async event => {
|
|||||||
game_domain: cleanHost || '',
|
game_domain: cleanHost || '',
|
||||||
lang_code: finalLocale,
|
lang_code: finalLocale,
|
||||||
}
|
}
|
||||||
|
|
||||||
const response = (await $fetch(apiUrl, {
|
const response = (await $fetch(apiUrl, {
|
||||||
query: queryParams,
|
query: queryParams,
|
||||||
})) as GameDataResponse | null
|
})) as GameDataResponse | null
|
||||||
@@ -288,14 +267,23 @@ export default defineEventHandler(async event => {
|
|||||||
setFinalLocaleCookie(event, finalLocale, baseDomain)
|
setFinalLocaleCookie(event, finalLocale, baseDomain)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (response?.code === 91001) {
|
||||||
|
// 91001 에러 발생 시 바로 /error 페이지로 리다이렉트
|
||||||
|
if (!event.node.res.headersSent && !event.node.res.writableEnded) {
|
||||||
|
const errorPath = `/${finalLocale || 'ko'}/error`
|
||||||
|
event.node.res.statusCode = 302
|
||||||
|
event.node.res.setHeader('Location', errorPath)
|
||||||
|
event.node.res.end()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (response?.code === 0 && 'value' in response) {
|
if (response?.code === 0 && 'value' in response) {
|
||||||
event.context.gameData = response.value
|
event.context.gameData = response.value
|
||||||
event.context.googleAnalyticsId = response.value?.ga_code
|
event.context.googleAnalyticsId = response.value?.ga_code
|
||||||
|
|
||||||
console.log('🚀 ~ gameData:', response.value)
|
|
||||||
|
|
||||||
// 점검 데이터 조회
|
// 점검 데이터 조회
|
||||||
let inspectionData
|
let inspectionData: WebInspectionData | undefined
|
||||||
if (cache.has(cacheKey)) {
|
if (cache.has(cacheKey)) {
|
||||||
inspectionData = cache.get(cacheKey) as WebInspectionData
|
inspectionData = cache.get(cacheKey) as WebInspectionData
|
||||||
} else {
|
} else {
|
||||||
@@ -333,50 +321,39 @@ export default defineEventHandler(async event => {
|
|||||||
) {
|
) {
|
||||||
/**
|
/**
|
||||||
* 점검 중인 경우
|
* 점검 중인 경우
|
||||||
* - 점검 상태가 1이고 현재 시간이 점검 시작과 종료 사이에 있는지 확인ㄹ
|
* - 점검 상태가 1이고 현재 시간이 점검 시작과 종료 사이에 있는지 확인
|
||||||
* - 점검 URL 경로가 아닐 경우 no-cache 설정
|
* - 점검 URL 경로가 아닐 경우 no-cache 설정
|
||||||
* - 화이트 리스트 체크
|
* - 화이트 리스트 체크
|
||||||
*/
|
*/
|
||||||
// 현재 경로가 점검 페이지가 아닐 경우 리다이렉트
|
|
||||||
const inspectionPath = `/${finalLocale}/inspection`
|
const inspectionPath = `/${finalLocale}/inspection`
|
||||||
if (fullPath !== inspectionPath) {
|
const isInspectionPath = fullPath === inspectionPath
|
||||||
|
|
||||||
|
// 현재 경로가 점검 페이지가 아닐 경우 캐시 헤더 설정
|
||||||
|
if (!isInspectionPath) {
|
||||||
setCacheHeaders(event, 'no-cache')
|
setCacheHeaders(event, 'no-cache')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 응답이 이미 종료되었는지 확인
|
||||||
|
if (event.node.res.headersSent || event.node.res.writableEnded) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// 점검 중일 때 IP 필터링 활성화 여부 확인
|
// 점검 중일 때 IP 필터링 활성화 여부 확인
|
||||||
if (inspectionData?.ip_filter_use_yn === 'Y') {
|
if (inspectionData?.ip_filter_use_yn === 'Y') {
|
||||||
const clientIP = getTrueClientIp(event.node.req as any)
|
const clientIP = getTrueClientIp(event.node.req as any)
|
||||||
|
|
||||||
// 점검 중일 때 IP 필터링 활성화 여부 확인
|
// 허용된 IP 목록 확인
|
||||||
if (inspectionData?.ip_filter_use_yn === 'Y') {
|
if (inspectionData?.ip_filter_list?.includes(clientIP)) {
|
||||||
const clientIP = getTrueClientIp(event.node.req as any)
|
// 화이트 리스트인 경우 Locale Middleware 실행
|
||||||
|
fnLocaleMiddleware(event, finalLocale)
|
||||||
// 허용된 IP 목록 확인
|
|
||||||
if (!inspectionData?.ip_filter_list?.includes(clientIP)) {
|
|
||||||
// 허용되지 않은 IP인 경우 점검 페이지로 이동
|
|
||||||
if (
|
|
||||||
!event.node.res.headersSent &&
|
|
||||||
!event.node.res.writableEnded
|
|
||||||
) {
|
|
||||||
event.node.res.statusCode = 302
|
|
||||||
event.node.res.setHeader('Location', inspectionPath)
|
|
||||||
event.node.res.end()
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// 화이트 리스트인 경우
|
|
||||||
// -------------------------------------------------------------------------------
|
|
||||||
// [Locale Middleware]
|
|
||||||
// -------------------------------------------------------------------------------
|
|
||||||
fnLocaleMiddleware(event, finalLocale)
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
if (!event.node.res.headersSent && !event.node.res.writableEnded) {
|
// 허용되지 않은 IP인 경우 점검 페이지로 이동
|
||||||
event.node.res.statusCode = 302
|
event.node.res.statusCode = 302
|
||||||
event.node.res.setHeader('Location', inspectionPath)
|
event.node.res.setHeader('Location', inspectionPath)
|
||||||
event.node.res.end()
|
event.node.res.end()
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
// IP 필터링이 비활성화된 경우 모든 사용자를 점검 페이지로 이동
|
||||||
event.node.res.statusCode = 302
|
event.node.res.statusCode = 302
|
||||||
event.node.res.setHeader('Location', inspectionPath)
|
event.node.res.setHeader('Location', inspectionPath)
|
||||||
event.node.res.end()
|
event.node.res.end()
|
||||||
@@ -443,37 +420,40 @@ export default defineEventHandler(async event => {
|
|||||||
fnLocaleMiddleware(event, finalLocale)
|
fnLocaleMiddleware(event, finalLocale)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error: any) {
|
||||||
console.error('gameData load error:', error)
|
console.error('gameData load error:', error)
|
||||||
|
|
||||||
// 500 에러 발생 시 /error 페이지로 리다이렉트
|
// 응답이 이미 종료되었는지 확인
|
||||||
if (!event.node.res.headersSent && !event.node.res.writableEnded) {
|
if (event.node.res.headersSent || event.node.res.writableEnded) {
|
||||||
// 언어 코드 추출 시도
|
return
|
||||||
let finalLocale = 'ko' // 기본값
|
|
||||||
try {
|
|
||||||
finalLocale = ssrGetFinalLocale(
|
|
||||||
event?.node.req.url,
|
|
||||||
event.node.req.headers,
|
|
||||||
initLangCodes,
|
|
||||||
initDefaultLocale
|
|
||||||
)
|
|
||||||
} catch (e) {
|
|
||||||
console.error('Locale extraction error:', e)
|
|
||||||
}
|
|
||||||
// finalLocale이 undefined인 경우 기본값으로 'ko' 설정
|
|
||||||
|
|
||||||
console.log('🚀 ~ 여기도 타? error:', error)
|
|
||||||
throw createError({
|
|
||||||
statusCode: error.statusCode,
|
|
||||||
statusMessage: error.statusMessage,
|
|
||||||
})
|
|
||||||
// if (!finalLocale) {
|
|
||||||
// finalLocale = 'ko'
|
|
||||||
// }
|
|
||||||
// const errorPath = `/${finalLocale}/error?message=${error.message}`
|
|
||||||
// event.node.res.statusCode = 302
|
|
||||||
// event.node.res.setHeader('Location', errorPath)
|
|
||||||
// event.node.res.end()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 언어 코드 추출 시도
|
||||||
|
let errorLocale = 'ko' // 기본값
|
||||||
|
try {
|
||||||
|
errorLocale = ssrGetFinalLocale(
|
||||||
|
event?.node.req.url,
|
||||||
|
event.node.req.headers,
|
||||||
|
initLangCodes,
|
||||||
|
initDefaultLocale
|
||||||
|
)
|
||||||
|
} catch (e) {
|
||||||
|
console.error('Locale extraction error:', e)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 91001 에러인 경우 바로 리다이렉트
|
||||||
|
if (error?.statusCode === 91001 || error?.cause?.statusCode === 91001) {
|
||||||
|
const errorPath = `/${errorLocale}/error`
|
||||||
|
event.node.res.statusCode = 302
|
||||||
|
event.node.res.setHeader('Location', errorPath)
|
||||||
|
event.node.res.end()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 다른 에러는 기존대로 throw
|
||||||
|
throw createError({
|
||||||
|
statusCode: error?.statusCode || 500,
|
||||||
|
statusMessage: error?.statusMessage,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -12,6 +12,7 @@
|
|||||||
".nuxt/nuxt.d.ts",
|
".nuxt/nuxt.d.ts",
|
||||||
".nuxt/auto-imports.d.ts",
|
".nuxt/auto-imports.d.ts",
|
||||||
"types/**/*",
|
"types/**/*",
|
||||||
|
"i18n/**/*",
|
||||||
"layers/**/*",
|
"layers/**/*",
|
||||||
"app/**/*"
|
"app/**/*"
|
||||||
, "temp/inspection.ts", "temp/middleware.ts" ],
|
, "temp/inspection.ts", "temp/middleware.ts" ],
|
||||||
|
|||||||
8
types/i18n.d.ts
vendored
Normal file
8
types/i18n.d.ts
vendored
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
declare global {
|
||||||
|
function defineI18nLocale(
|
||||||
|
loader: (locale: string) => Promise<Record<string, any>> | Record<string, any>
|
||||||
|
): any
|
||||||
|
}
|
||||||
|
|
||||||
|
export {}
|
||||||
|
|
||||||
Reference in New Issue
Block a user