From 08a0e59ae186763814bccddd5fbca7165cffffa1 Mon Sep 17 00:00:00 2001 From: mina-gwak Date: Tue, 20 May 2025 23:09:47 +0900 Subject: [PATCH 1/4] =?UTF-8?q?Chore:=20=ED=85=8C=EC=8A=A4=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- vercel.json | 24 ------------------------ 1 file changed, 24 deletions(-) diff --git a/vercel.json b/vercel.json index 223c2b3..3e9941d 100644 --- a/vercel.json +++ b/vercel.json @@ -1,29 +1,5 @@ { - "headers": [ - { - "source": "/api/(.*)", - "headers": [ - { - "key": "Access-Control-Allow-Origin", - "value": "https://www.dev.admin.plus82.co" - }, - { - "key": "Access-Control-Allow-Methods", - "value": "GET, POST, OPTIONS" - }, - { - "key": "Access-Control-Allow-Headers", - "value": "Content-Type, Authorization" - }, - { "key": "Access-Control-Allow-Credentials", "value": "true" } - ] - } - ], "rewrites": [ - { - "source": "/api/:path*", - "destination": "https://dev.back.plus82.co/api/:path*" - }, { "source": "/cdn/:path*", "destination": "https://d1zl1w0yhwh5x4.cloudfront.net/:path*" From f2ea7dae6cf32341cd0e709785159cd518b6c609 Mon Sep 17 00:00:00 2001 From: mina-gwak Date: Tue, 20 May 2025 23:25:45 +0900 Subject: [PATCH 2/4] =?UTF-8?q?Chore:=20dev,=20production=20api=20path=20?= =?UTF-8?q?=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api/instance.ts | 274 +++++++++++++++++++++++++------------------- vercel.json | 8 ++ vite.config.ts | 7 +- 3 files changed, 167 insertions(+), 122 deletions(-) diff --git a/src/api/instance.ts b/src/api/instance.ts index a3e945e..1bd3e7f 100644 --- a/src/api/instance.ts +++ b/src/api/instance.ts @@ -1,153 +1,167 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ -import axios from "axios"; -import fileDownload from "js-file-download"; -import qs from "qs"; +import axios from 'axios' +import fileDownload from 'js-file-download' +import qs from 'qs' import { getCookie } from 'typescript-cookie' -import { HttpError } from "@/api/error/http-error"; -import type { CommonResponse, SuccessResponse } from "@/api/response/common"; -import { CommonResponseCode } from "@/api/response/response-code"; - -import type { AxiosInstance, AxiosPromise } from "axios"; +import { HttpError } from '@/api/error/http-error' +import type { CommonResponse, SuccessResponse } from '@/api/response/common' +import { CommonResponseCode } from '@/api/response/response-code' +import type { AxiosInstance, AxiosPromise } from 'axios' export enum ContentType { - JSON = "application/json", - MULTIPART = "multipart/form-data", - URLENCODED = "application/x-www-form-urlencoded", + JSON = 'application/json', + MULTIPART = 'multipart/form-data', + URLENCODED = 'application/x-www-form-urlencoded', } type AxiosMethodType = { - url: string; - data?: any; - contentType?: ContentType; -}; + url: string + data?: any + contentType?: ContentType +} -const DEFAULT_ERROR_MESSAGE = "기술팀에 문의해주세요"; +const DEFAULT_ERROR_MESSAGE = '기술팀에 문의해주세요' const ERROR_MESSAGES = { - 500: "기술팀에 문의해주세요", -}; + 500: '기술팀에 문의해주세요', +} class CustomAxios { - private instance: AxiosInstance; + private instance: AxiosInstance constructor(baseURL?: string) { this.instance = axios.create({ baseURL: baseURL ?? window.location.origin, timeout: 15000, headers: { - "Content-Type": ContentType.JSON, + 'Content-Type': ContentType.JSON, }, - }); + }) this.instance.interceptors.request.use( config => config, - error => Promise.reject(error) - ); + error => Promise.reject(error), + ) this.instance.interceptors.response.use( response => { - const commonResponse: CommonResponse = response.data; + const commonResponse: CommonResponse = response.data if ( commonResponse.code !== CommonResponseCode.SUCCESS && !(commonResponse instanceof Blob) ) { - throw new HttpError({ ...commonResponse, status: response.status }); + throw new HttpError({ ...commonResponse, status: response.status }) } - if (response.config.method === "get" && response.data instanceof Blob) { - return response; + if (response.config.method === 'get' && response.data instanceof Blob) { + return response } - return response.data; + return response.data }, async error => { - const status = error?.response?.status; + const status = error?.response?.status if (error.response.data instanceof Blob) { const commonResponse: CommonResponse = JSON.parse( - await error.response.data.text() - ); + await error.response.data.text(), + ) throw new HttpError({ ...commonResponse, status, - }); + }) } else if (status >= 400 && status < 500) { - const { code, data, message } = error.response.data; - throw new HttpError({ code, data, message, status }); + const { code, data, message } = error.response.data + throw new HttpError({ code, data, message, status }) } else { throw new HttpError({ code: status, - message: ERROR_MESSAGES[status as keyof typeof ERROR_MESSAGES] ?? DEFAULT_ERROR_MESSAGE, + message: + ERROR_MESSAGES[status as keyof typeof ERROR_MESSAGES] ?? + DEFAULT_ERROR_MESSAGE, status, - }); + }) } - } - ); + }, + ) } // Authorization 헤더를 동적으로 추가 - private addAuth(headers: Record, useAuth: boolean): Record { + private addAuth( + headers: Record, + useAuth: boolean, + ): Record { if (useAuth) { - const token = getCookie("Authorization"); + const token = getCookie('Authorization') if (token) { - headers["Authorization"] = `Bearer ${token}`; + headers['Authorization'] = `Bearer ${token}` } } - return headers; + return headers } - async get({ url, data, useAuth = true }: AxiosMethodType & { useAuth?: boolean }): Promise { - const queryParam = qs.stringify(data, { arrayFormat: "repeat" }); - const newUrl = queryParam ? `${url}?${queryParam}` : url; + async get({ + url, + data, + useAuth = true, + }: AxiosMethodType & { useAuth?: boolean }): Promise { + const queryParam = qs.stringify(data, { arrayFormat: 'repeat' }) + const newUrl = queryParam ? `${url}?${queryParam}` : url - const headers = this.addAuth({}, useAuth); - const commonResponse: SuccessResponse = await this.instance.get(newUrl, { headers }); + const headers = this.addAuth({}, useAuth) + const commonResponse: SuccessResponse = await this.instance.get(newUrl, { + headers, + }) - return commonResponse.data; + return commonResponse.data } - async getPaged({ url, data, useAuth = true }: AxiosMethodType & { useAuth?: boolean }): Promise<{ - content: T[]; + async getPaged({ + url, + data, + useAuth = true, + }: AxiosMethodType & { useAuth?: boolean }): Promise<{ + content: T[] pageable: { - pageNumber: number; - pageSize: number; - offset: number; - paged: boolean; - unpaged: boolean; - }; - totalElements: number; - totalPages: number; - first: boolean; - last: boolean; - numberOfElements: number; - empty: boolean; + pageNumber: number + pageSize: number + offset: number + paged: boolean + unpaged: boolean + } + totalElements: number + totalPages: number + first: boolean + last: boolean + numberOfElements: number + empty: boolean }> { - const queryParam = qs.stringify(data, { arrayFormat: "repeat" }); - const newUrl = queryParam ? `${url}?${queryParam}` : url; + const queryParam = qs.stringify(data, { arrayFormat: 'repeat' }) + const newUrl = queryParam ? `${url}?${queryParam}` : url - const headers = this.addAuth({}, useAuth); + const headers = this.addAuth({}, useAuth) const commonResponse: SuccessResponse<{ - content: T[]; + content: T[] pageable: { - pageNumber: number; - pageSize: number; - offset: number; - paged: boolean; - unpaged: boolean; - }; - totalElements: number; - totalPages: number; - first: boolean; - last: boolean; - numberOfElements: number; - empty: boolean; - }> = await this.instance.get(newUrl, { headers }); - - return commonResponse.data; + pageNumber: number + pageSize: number + offset: number + paged: boolean + unpaged: boolean + } + totalElements: number + totalPages: number + first: boolean + last: boolean + numberOfElements: number + empty: boolean + }> = await this.instance.get(newUrl, { headers }) + + return commonResponse.data } async post({ @@ -157,13 +171,17 @@ class CustomAxios { useAuth = true, }: AxiosMethodType & { useAuth?: boolean }): Promise { const headers = this.addAuth( - { "Content-Type": contentType ?? ContentType.JSON }, - useAuth - ); + { 'Content-Type': contentType ?? ContentType.JSON }, + useAuth, + ) - const commonResponse: SuccessResponse = await this.instance.post(url, data, { headers }); + const commonResponse: SuccessResponse = await this.instance.post( + url, + data, + { headers }, + ) - return commonResponse.data; + return commonResponse.data } async postMultipart({ @@ -172,13 +190,17 @@ class CustomAxios { useAuth = true, }: AxiosMethodType & { useAuth?: boolean }): Promise { const headers = this.addAuth( - { "Content-Type": ContentType.MULTIPART }, - useAuth - ); + { 'Content-Type': ContentType.MULTIPART }, + useAuth, + ) - const commonResponse: SuccessResponse = await this.instance.post(url, data, { headers }); + const commonResponse: SuccessResponse = await this.instance.post( + url, + data, + { headers }, + ) - return commonResponse.data; + return commonResponse.data } async putMultipart({ @@ -187,13 +209,17 @@ class CustomAxios { useAuth = true, }: AxiosMethodType & { useAuth?: boolean }): Promise { const headers = this.addAuth( - { "Content-Type": ContentType.MULTIPART }, - useAuth - ); + { 'Content-Type': ContentType.MULTIPART }, + useAuth, + ) - const commonResponse: SuccessResponse = await this.instance.put(url, data, { headers }); + const commonResponse: SuccessResponse = await this.instance.put( + url, + data, + { headers }, + ) - return commonResponse.data; + return commonResponse.data } async put({ @@ -203,51 +229,57 @@ class CustomAxios { useAuth = true, }: AxiosMethodType & { useAuth?: boolean }): Promise { const headers = this.addAuth( - { "Content-Type": contentType ?? ContentType.JSON }, - useAuth - ); + { 'Content-Type': contentType ?? ContentType.JSON }, + useAuth, + ) - const commonResponse: SuccessResponse = await this.instance.put(url, data, { headers }); + const commonResponse: SuccessResponse = await this.instance.put( + url, + data, + { headers }, + ) - return commonResponse.data; + return commonResponse.data } - async delete({ url, data, useAuth = true }: AxiosMethodType & { useAuth?: boolean }): Promise { - const headers = this.addAuth({}, useAuth); + async delete({ + url, + data, + useAuth = true, + }: AxiosMethodType & { useAuth?: boolean }): Promise { + const headers = this.addAuth({}, useAuth) const commonResponse: SuccessResponse = await this.instance.delete(url, { data, headers, - }); + }) - return commonResponse.data; + return commonResponse.data } async download({ url, data }: AxiosMethodType): AxiosPromise { - const queryParam = qs.stringify(data); - const newUrl = queryParam ? `${url}?${queryParam}` : url; + const queryParam = qs.stringify(data) + const newUrl = queryParam ? `${url}?${queryParam}` : url const response = await this.instance.get(newUrl, { - responseType: "blob", - }); + responseType: 'blob', + }) // 에러 발생시에는 데이터 타입이 JSON 형태로 내려옴 if (response.data instanceof Blob) { - const contentDisposition = response.headers["content-disposition"]; - const fileName = contentDisposition?.match( - /filename[*]=UTF-8''(.+)/ - )?.[1]; - if (fileName) fileDownload(response.data, decodeURI(fileName)); + const contentDisposition = response.headers['content-disposition'] + const fileName = contentDisposition?.match(/filename[*]=UTF-8''(.+)/)?.[1] + if (fileName) fileDownload(response.data, decodeURI(fileName)) } - return response.data; + return response.data } } -const baseURL = `${window.location.origin}/api/v1/`; -// const baseURL = `http://localhost:8080/api/v1/`; -// const baseURL = `https://dev.back.plus82.co/api/v1/`; - +const baseURL = + process.env.NODE_ENV === 'development' + ? `${window.location.origin}/dev/api/v1/` + : `${window.location.origin}/api/v1/` -const http = new CustomAxios(baseURL); +const http = new CustomAxios(baseURL) -export default http; +export default http diff --git a/vercel.json b/vercel.json index 3e9941d..9a4e8cd 100644 --- a/vercel.json +++ b/vercel.json @@ -1,5 +1,13 @@ { "rewrites": [ + { + "source": "/dev/api/:path*", + "destination": "https://dev.back.plus82.co/api/:path*" + }, + { + "source": "/api/:path*", + "destination": "https://back.plus82.co/api/:path*" + }, { "source": "/cdn/:path*", "destination": "https://d1zl1w0yhwh5x4.cloudfront.net/:path*" diff --git a/vite.config.ts b/vite.config.ts index b8dc888..a8f5861 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -12,9 +12,14 @@ export default defineConfig({ }, server: { proxy: { - '/api': { + '/dev/api': { target: 'https://dev.back.plus82.co', changeOrigin: true, + rewrite: path => path.replace(/^\/dev/, ''), + }, + '/api': { + target: 'https://back.plus82.co', + changeOrigin: true, }, '/cdn': { target: `https://d1zl1w0yhwh5x4.cloudfront.net`, From 3b25d28ac3eebdc6c2bd52e41286c9db1d1e7bfc Mon Sep 17 00:00:00 2001 From: mina-gwak Date: Tue, 20 May 2025 23:43:28 +0900 Subject: [PATCH 3/4] =?UTF-8?q?Fix:=20=ED=99=98=EA=B2=BD=EB=B3=80=EC=88=98?= =?UTF-8?q?=20=EA=B0=80=EC=A0=B8=EC=98=A4=EB=8A=94=20=EB=B0=A9=EC=8B=9D=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api/instance.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/api/instance.ts b/src/api/instance.ts index 1bd3e7f..ad4239d 100644 --- a/src/api/instance.ts +++ b/src/api/instance.ts @@ -276,9 +276,9 @@ class CustomAxios { } const baseURL = - process.env.NODE_ENV === 'development' - ? `${window.location.origin}/dev/api/v1/` - : `${window.location.origin}/api/v1/` + import.meta.env.ENVIRONMENT === 'production' + ? `${window.location.origin}/api/v1/` + : `${window.location.origin}/dev/api/v1/` const http = new CustomAxios(baseURL) From a128b04ab6bceeaf0369b7ccb6090f4cf322ff4a Mon Sep 17 00:00:00 2001 From: mina-gwak Date: Tue, 20 May 2025 23:52:51 +0900 Subject: [PATCH 4/4] =?UTF-8?q?Fix:=20=ED=99=98=EA=B2=BD=EB=B3=80=EC=88=98?= =?UTF-8?q?=EB=AA=85=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api/instance.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/instance.ts b/src/api/instance.ts index ad4239d..f056e6a 100644 --- a/src/api/instance.ts +++ b/src/api/instance.ts @@ -276,7 +276,7 @@ class CustomAxios { } const baseURL = - import.meta.env.ENVIRONMENT === 'production' + import.meta.env.VITE_ENVIRONMENT === 'production' ? `${window.location.origin}/api/v1/` : `${window.location.origin}/dev/api/v1/`