refactor: 에러 처리 완료, 페이지 접근 api 미들웨어로 수정

This commit is contained in:
“hyeonggkim”
2025-11-11 19:08:58 +09:00
parent 65c79eb689
commit 5c81f5d4d6
12 changed files with 318 additions and 276 deletions

View File

@@ -7,24 +7,29 @@ export default defineNuxtRouteMiddleware(async (to, _from) => {
}
// 현재 경로에서 언어 코드 추출
// 예: /ko/about/story -> ko
// 예: /en/test/page -> en
const gameDataStore = useGameDataStore()
const gameData = gameDataStore.gameData as GameDataValue
const langCodes = gameData?.lang_codes
const currentLangCode = csrGetFinalLocale(to.path, langCodes)
const { getPathAfterLanguage } = usePathResolver()
const pageUrl = getPathAfterLanguage(to.path)
// const languagePattern = /^\/([a-z]{2})(?:\/|$)/
// const match = to.path.match(languagePattern)
// const currentLangCode = match ? match[1] : null
console.log("🚀 777777 ~ currentLangCode:", currentLangCode)
//현재 url에서 게임 도메인만 추출
const currentDomain = window.location.hostname
const runtimeConfig = useRuntimeConfig()
// 쿼리스트링에서 f 파라미터 값 추출 (CSR용)
const fValue = (to.query.f as string) || ''
// 미리보기 API 호출 처리
let finalGameDomain = currentDomain
if (fValue === 'preview') {
finalGameDomain = 'samplegame.onstove.com'
}
const req: GameDataRequest = {
gameDomain: `${currentDomain}`,
gameDomain: `${finalGameDomain}`,
langCode: `${currentLangCode}`,
game_alias: '',
lang_code: `${currentLangCode}`,
@@ -34,16 +39,19 @@ export default defineNuxtRouteMiddleware(async (to, _from) => {
const { getGameDataExternal } = useGetGameDataExternal()
await getGameDataExternal(req)
// 허용된 언어 코드 목록≈≈
const allowedLangCodes = langCodes || []
// error 페이지는 API 호출하지 않음
if (pageUrl === '/error' || to.path.includes('/error')) {
return
}
// 현재 언어가 허용된 언어 목록에 없으면 에러 페이지로 이동
if (currentLangCode && !allowedLangCodes.includes(currentLangCode)) {
throw createError({
statusCode: 404,
statusMessage: 'Language not supported',
})
return navigateTo(`/${currentLangCode}/error`, { external: false })
// throw createError({
// statusCode: 404,
// statusMessage: 'Language not supported11',
// })
}
})

View File

@@ -1,6 +1,19 @@
export default defineNuxtRouteMiddleware(async to => {
try {
//error 발생시에는 미들웨어 실행하지 않음
//error 객체 조회
if (import.meta.client) {
const error = useError()
if(error.value?.statusCode){
return showError(createError({
statusCode: error.value?.statusCode,
statusMessage: error.value?.message,
fatal: true,
// data: { path: to.path }
}))
}
const gameDataStore = useGameDataStore()
const { gameData } = storeToRefs(gameDataStore)
console.log('🚀 ~ 00000 gameData:', gameData.value)
@@ -40,6 +53,7 @@ export default defineNuxtRouteMiddleware(async to => {
!to.path.includes('inspection') &&
!to.path.includes('api')
) {
console.log('e111111111 eee')
// 점검 중인 경우
return navigateTo(`/${finalLocale}/inspection`, { external: true })
} else if (
@@ -47,8 +61,11 @@ export default defineNuxtRouteMiddleware(async to => {
to.path?.indexOf('inspection') !== -1
) {
// 점검이 종료된 후 점검 페이지 접근시 메인으로 리다이렉트
console.log('ddddd 222222')
return navigateTo(`/${finalLocale}`, { external: true })
}
console.log('33333333 eee')
}
} catch (e) {
console.error('[Exception] /middleware/inspection: ', e)

View File

@@ -6,7 +6,7 @@ import type { PageDataResponse } from '#layers/types/api/pageData'
import type { GameDataValue } from '#layers/types/api/gameData'
export default defineNuxtRouteMiddleware(async (to, _from) => {
// [TODO] 하이드레이션 에러 처리
// client에서만 동작되도록 처리
if (!import.meta.client) return
const runtimeConfig = useRuntimeConfig()
@@ -28,10 +28,7 @@ export default defineNuxtRouteMiddleware(async (to, _from) => {
)
try {
// 서버 사이드에서는 스킵
if (import.meta.server) {
return
}
if (to.path.includes('inspection')) {
return
}
@@ -45,11 +42,26 @@ export default defineNuxtRouteMiddleware(async (to, _from) => {
// pageUrl이 빈값이거나 null이면 /brand로 리다이렉트
if (!pageUrl || pageUrl === '' || pageUrl === '/' || pageUrl === `/${langCode}/`) {
return navigateTo(`/${langCode}/brand`, { replace: true })
return navigateTo(`/${langCode}/brand`, { external: false })
}
const accessToken = csrGetAccessToken()
const headers = {
Authorization: `Bearer ${accessToken}`,
}
// 쿼리스트링에서 f 파라미터 값 추출 (CSR용)
const fValue = (to.query.f as string) || ''
// 미리보기 API 호출 처리
let finalGameDomain = gameDomain
if (fValue === 'preview') {
finalGameDomain = 'samplegame.onstove.com'
}
const queryParams: Record<string, string> = {
game_domain: gameDomain,
game_domain: finalGameDomain,
lang_code: langCode,
page_url: pageUrl,
_t: Date.now().toString(), // 캐시 무효화를 위한 타임스탬프
@@ -57,13 +69,37 @@ export default defineNuxtRouteMiddleware(async (to, _from) => {
// console.log('🚀 ~ queryParams:', queryParams)
const response = (await commonFetch('GET', apiUrl, {
headers,
query: queryParams,
loading: true,
})) as PageDataResponse | null
console.log('🚀 ~ response?.code:', response?.code)
// 페이지 접근 권한 설정(로그인 유무)
if(response?.value?.is_login_required === 1 && !accessToken) {
// 로그인 레이어 팝업 띄워주기
const nuxtApp = useNuxtApp()
const modalStore = useModalStore()
const $i18n = nuxtApp.$i18n as any
const {tm} = $i18n
modalStore.handleOpenConfirm({
contentText: tm('Alert_StoveLogin'),
confirmButtonText: tm('Text_StoveLogin'),
confirmButtonEvent: () => {
csrGoStoveLogin()
},
})
}
if(response?.code === 91003) {
return navigateTo(`/${langCode}/error`, { external: false })
// return navigateTo(`/${langCode}/error`, { external: false })
showError(createError({
statusCode: 404,
statusMessage: '페이지를 찾을 수 없어요.',
fatal: false, // 즉시 에러 페이지로
data: { reason: 'post-not-found' }
}))
}
if (response?.code === 0 && 'value' in response) {
@@ -74,5 +110,12 @@ export default defineNuxtRouteMiddleware(async (to, _from) => {
} catch (error) {
console.error(error)
store.clearPageData()
showError(createError({
statusCode: error.statusCode,
statusMessage: error.message,
fatal: false, // 즉시 에러 페이지로
data: { reason: 'post-not-found' }
}))
}
})

View File

@@ -1,12 +0,0 @@
export default defineNuxtPlugin((nuxtApp) => {
nuxtApp.vueApp.config.errorHandler = (error, instance, info) => {
console.log("🚀 000000 ~ error:", error)
// handle error, e.g. report to a service
}
// Also possible
nuxtApp.hook('vue:error', (error, instance, info) => {
console.log("🚀1111 ~ error:", error)
// handle error, e.g. report to a service
})
})

View File

@@ -96,6 +96,7 @@ function fnLocaleMiddleware(event: any, finalLocale: string) {
// 쿼리스트링 포함 시 순수 경로만 추출
arrPath = path.split('?')[0].split('/')
queryString = path.split('?')[1]
} else {
arrPath = path.split('/')
queryString = ''
@@ -238,6 +239,33 @@ export default defineEventHandler(async event => {
// 2. 언어 코드 추출
finalLocale = ssrGetFinalLocale(event?.node.req.url, event.node.req.headers, initLangCodes, initDefaultLocale)
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)
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'
}
const queryParams: Record<string, string> = {
game_domain: cleanHost || '',
@@ -385,5 +413,35 @@ export default defineEventHandler(async event => {
}
} catch (error) {
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()
}
}
})

View File

@@ -47,6 +47,7 @@ const checkLoginValidation = async () => {
const validateTokenResult = await handleTokenValidation(
accessToken.value || ''
)
console.log("🚀 ~ checkLoginValidation ~ validateTokenResult:", validateTokenResult)
isLogin.value = validateTokenResult
}

View File

@@ -28,6 +28,7 @@ export interface PageDataValue {
page_name: string
page_name_en: string
page_ver: string
is_login_required: number
meta_tag_type: number
fit_page_height: boolean
use_top_btn: boolean