Files
web-temp/layers/utils/apiUtil.ts

181 lines
4.3 KiB
TypeScript

import { ref } from 'vue'
/**
* 공통 API 호출
*
* @param {string} method - 요청 메소드 (GET, POST 등)
* @param {string} url - API URL
* @param {object} query - 요청 쿼리 파라미터
* @param {object} headers - 요청 헤더
* @param {object} body - 요청 본문
* @param {string} key - 캐시 키
* @param {object} loading - 로딩 설정
*/
export const commonFetch = async (
method:
| 'GET'
| 'HEAD'
| 'PATCH'
| 'POST'
| 'PUT'
| 'DELETE'
| 'CONNECT'
| 'OPTIONS'
| 'TRACE' = 'GET', // Required
url: string, // Required
{
query, // Optional
headers, // Optional
body, // Optional
key, // Optional
loading = false, // Optional
}: {
query?: object | null
headers?: object | null
body?: object | null
key?: string | null
loading?: { localId?: string } | boolean
} = {}
) => {
let result = null
const currCallerId = ref('')
const currCallerDetail = ref('')
// 로딩 스토어 가져오기 (클라이언트에서만)
let loadingStore: ReturnType<typeof useLoadingStore> | null = null
if (import.meta.client) {
try {
loadingStore = useLoadingStore()
// 로딩 시작
loadingStore.setLoading(true)
if (loading && loadingStore) {
if (typeof loading === 'object' && loading.localId) {
loadingStore.startLocalLoading(loading.localId)
} else {
loadingStore.startFullLoading()
}
}
} catch (e) {
console.warn('[Warning] Loading store not available:', e)
}
}
try {
const { callerId, callerDetail } = storeToRefs(useCallerInfoStore())
currCallerId.value = `${callerId.value}`
currCallerDetail.value = `${callerDetail.value}`
} catch (e) {
// SSR: pinia store 생성 전이므로 빈 값('') 세팅
}
try {
const options: {
method:
| 'GET'
| 'HEAD'
| 'PATCH'
| 'POST'
| 'PUT'
| 'DELETE'
| 'CONNECT'
| 'OPTIONS'
| 'TRACE'
headers: Record<string, string>
query?: object
body?: object
key?: string
} = {
method,
headers: {
'Content-Type': 'application/json;charset=UTF-8',
},
}
if (query) {
options.query = query
}
// 플랫폼 환경 API 호출 시 Caller-Id, Caller-Detail 헤더 추가
if (url.includes('.onstove.com') || url.includes('.gate8.com')) {
const callerInfo = {
'Caller-Id': `${currCallerId.value}`,
'Caller-Detail': `${currCallerDetail.value}`,
}
options.headers = { ...options.headers, ...callerInfo }
}
if (headers) {
options.headers = { ...options.headers, ...headers }
}
if (body) {
options.body = body
}
if (key) {
options.key = key
}
result = await $fetch(url, options)
} catch (e: unknown) {
console.error('[Exception] apiUtil.commonFetch: ', e)
const error = e as {
data?: unknown
statusCode?: number
statusMessage?: string
}
result = error.data || {
code: error.statusCode,
message: error.statusMessage,
}
} finally {
// 로딩 종료
if (loadingStore) {
loadingStore.setLoading(false)
if (loading) {
if (typeof loading === 'object' && loading.localId) {
loadingStore.stopLocalLoading(loading.localId)
} else {
loadingStore.stopFullLoading()
}
}
}
}
return result
}
/**
* 사용자 IP 조회
*
* @param {object} request - 요청 객체
*/
export const getTrueClientIp = (request: {
headers: Record<string, string>
socket: { remoteAddress?: string }
}) => {
const requestHeaders = request.headers
const targetHeaders = [
'True-Client-IP',
'X-Real-IP',
'X-Forwarded-For',
'Proxy-Client-IP',
'WL-Proxy-Client-IP',
'HTTP_CLIENT_IP',
'HTTP_X_FORWARDED_FOR',
]
for (const targetHeader of targetHeaders) {
let ip =
requestHeaders[targetHeader] || requestHeaders[targetHeader.toLowerCase()]
if (ip !== undefined && ip != null && ip !== '') {
if (ip.includes(',')) {
ip = ip.split(',')[0]
}
return ip
}
}
if (
request.socket.remoteAddress !== undefined &&
request.socket.remoteAddress != null &&
request.socket.remoteAddress !== ''
) {
return request.socket.remoteAddress
}
return ''
}