refactor: gamedata 없을 때 error 페이지 노출 수정, 다국어 파일 경로 수정

This commit is contained in:
“hyeonggkim”
2025-11-19 20:56:41 +09:00
parent 1726ddb15d
commit f29b84e8e1
18 changed files with 230 additions and 167 deletions

View File

@@ -59,6 +59,16 @@ export default defineNuxtRouteMiddleware(async (to, _from) => {
to.path.includes('/error') ||
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
}

View File

@@ -11,6 +11,7 @@ export default defineNuxtRouteMiddleware(async to => {
// error 페이지는 API 호출하지 않음
if (pageUrl === '/error' || to.path.includes('/error')) {
console.log("🚀 ~ inspection error 페이지는 API 호출하지 않음")
return
}
@@ -37,8 +38,6 @@ export default defineNuxtRouteMiddleware(async to => {
baseApiUrl: stoveApiBaseUrl,
gameId: stoveGameId,
})
console.log("🚀 ~ stoveApiBaseUrl:", stoveApiBaseUrl)
console.log("🚀 ~ stoveGameId:", stoveGameId)
// 게임 점검 -----
// const { checkGameMaintenance } = useGetGameMaintenance()

View File

@@ -42,6 +42,7 @@ export default defineNuxtRouteMiddleware(async (to, _from) => {
// error 페이지는 API 호출하지 않음
if (pageUrl === '/error' || to.path.includes('/error')) {
console.log("🚀 ~pageData.global error 페이지는 API 호출하지 않음")
return
}
// 페이지 이동 시 로딩 상태 시작

View File

@@ -1,9 +1,17 @@
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 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 { getTrueClientIp } from '#layers/utils/apiUtil'
/**
* 캐시 제어 헤더를 설정하는 공통 함수
@@ -68,7 +76,7 @@ const cache = new LRUCache({
* @param baseDomain - 기본 도메인
*/
function setFinalLocaleCookie(
event: any,
event: H3Event,
finalLocale: string,
baseDomain: string
) {
@@ -85,7 +93,7 @@ function setFinalLocaleCookie(
* @param event - 이벤트 객체
* @param finalLocale - 최종 언어
*/
function fnLocaleMiddleware(event: any, finalLocale: string) {
function fnLocaleMiddleware(event: H3Event, finalLocale: string) {
// 이미 응답이 종료되었는지 확인
if (event.node.res.headersSent || event.node.res.writableEnded) {
return
@@ -133,43 +141,24 @@ export default defineEventHandler(async event => {
return
}
if (event.path.includes('/error')) {
return
}
// 이미 응답이 종료되었는지 확인 (리다이렉트 등으로 인한 중복 실행 방지)
if (event.node.res.headersSent || event.node.res.writableEnded) {
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 iBaseApiUrl = `${runtimeConfig.public.stoveApiUrlServer}`
const baseDomain = `${runtimeConfig.public.baseDomain}`
const stoveApiUrlBaseServer = runtimeConfig.public.stoveApiUrlServer
const apiUrl = `${stoveApiUrlBaseServer}/pub-comm/v1.0/template/game`
const iBaseApiUrl = runtimeConfig.public.stoveApiUrlServer
const baseDomain = runtimeConfig.public.baseDomain
const apiUrl = `${iBaseApiUrl}/pub-comm/v1.0/template/game`
let initGameData: GameDataResponse | null = null
let initLangCodes: string[] | null = null
let finalLocale
let cleanHost
let initDefaultLocale
let finalLocale: string
let cleanHost: string | undefined
let initDefaultLocale: string | null = null
const host =
(getHeader(event, 'host') || getRequestHost(event)).toString() || ''
@@ -188,14 +177,13 @@ export default defineEventHandler(async event => {
const initResponse = (await $fetch(apiUrl, {
query: queryParams,
})) as GameDataResponse | null
initGameData = initResponse || null
// console.log("🚀 ~ 00000 initGameData:", initGameData)
initLangCodes = initResponse?.value?.lang_codes || null
initDefaultLocale = initResponse?.value?.default_lang_code || null
console.log('🚀 ~ initLangCodes:===========', initLangCodes)
} catch (error) {
console.error('init gameData load error:', error)
return
}
const fullPath = event.path
@@ -247,28 +235,19 @@ export default defineEventHandler(async event => {
initDefaultLocale
)
// 쿼리스트링에서 f 파라미터 값 추출
const path = event?.node.req.url || ''
let queryStringF = ''
let fValue = ''
let test500 = false
if (path.includes('?')) {
queryStringF = path.split('?')[1]
// 쿼리스트링에서 f 파라미터 값 추출
try {
const urlParams = new URLSearchParams(queryStringF)
const queryString = path.split('?')[1]
const urlParams = new URLSearchParams(queryString)
fValue = urlParams.get('f') || ''
// 테스트용 500 에러 발생 (예: ?test500=true)
test500 = urlParams.get('test500') === 'true'
} catch (e) {
console.error('쿼리스트링 파싱 에러:', e)
}
}
// 테스트용 500 에러 발생
if (test500) {
throw new Error('테스트용 500 에러 발생')
}
// 미리보기 API 호출 처리
if (fValue === 'preview') {
cleanHost = 'samplegame.onstove.com'
@@ -278,7 +257,7 @@ export default defineEventHandler(async event => {
game_domain: cleanHost || '',
lang_code: finalLocale,
}
const response = (await $fetch(apiUrl, {
query: queryParams,
})) as GameDataResponse | null
@@ -288,14 +267,23 @@ export default defineEventHandler(async event => {
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) {
event.context.gameData = response.value
event.context.googleAnalyticsId = response.value?.ga_code
console.log('🚀 ~ gameData:', response.value)
// 점검 데이터 조회
let inspectionData
let inspectionData: WebInspectionData | undefined
if (cache.has(cacheKey)) {
inspectionData = cache.get(cacheKey) as WebInspectionData
} else {
@@ -333,50 +321,39 @@ export default defineEventHandler(async event => {
) {
/**
* 점검 중인 경우
* - 점검 상태가 1이고 현재 시간이 점검 시작과 종료 사이에 있는지 확인
* - 점검 상태가 1이고 현재 시간이 점검 시작과 종료 사이에 있는지 확인
* - 점검 URL 경로가 아닐 경우 no-cache 설정
* - 화이트 리스트 체크
*/
// 현재 경로가 점검 페이지가 아닐 경우 리다이렉트
const inspectionPath = `/${finalLocale}/inspection`
if (fullPath !== inspectionPath) {
const isInspectionPath = fullPath === inspectionPath
// 현재 경로가 점검 페이지가 아닐 경우 캐시 헤더 설정
if (!isInspectionPath) {
setCacheHeaders(event, 'no-cache')
}
// 응답이 이미 종료되었는지 확인
if (event.node.res.headersSent || event.node.res.writableEnded) {
return
}
// 점검 중일 때 IP 필터링 활성화 여부 확인
if (inspectionData?.ip_filter_use_yn === 'Y') {
const clientIP = getTrueClientIp(event.node.req as any)
// 점검 중일 때 IP 필터링 활성화 여부 확인
if (inspectionData?.ip_filter_use_yn === 'Y') {
const clientIP = getTrueClientIp(event.node.req as any)
// 허용된 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)
}
// 허용된 IP 목록 확인
if (inspectionData?.ip_filter_list?.includes(clientIP)) {
// 화이트 리스트인 경우 Locale Middleware 실행
fnLocaleMiddleware(event, finalLocale)
} else {
if (!event.node.res.headersSent && !event.node.res.writableEnded) {
event.node.res.statusCode = 302
event.node.res.setHeader('Location', inspectionPath)
event.node.res.end()
}
// 허용되지 않은 IP인 경우 점검 페이지로 이동
event.node.res.statusCode = 302
event.node.res.setHeader('Location', inspectionPath)
event.node.res.end()
}
} else {
// IP 필터링이 비활성화된 경우 모든 사용자를 점검 페이지로 이동
event.node.res.statusCode = 302
event.node.res.setHeader('Location', inspectionPath)
event.node.res.end()
@@ -443,37 +420,40 @@ export default defineEventHandler(async event => {
fnLocaleMiddleware(event, finalLocale)
}
}
} catch (error) {
} catch (error: any) {
console.error('gameData load error:', error)
// 500 에러 발생 시 /error 페이지로 리다이렉트
if (!event.node.res.headersSent && !event.node.res.writableEnded) {
// 언어 코드 추출 시도
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()
// 응답이 이미 종료되었는지 확인
if (event.node.res.headersSent || event.node.res.writableEnded) {
return
}
// 언어 코드 추출 시도
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,
})
}
})