스프린트 진행중 프론트와 백엔드 API 연결 테스트 중 CORS를 만나게 되었다. 백엔드 개발자분 께서 응답 헤더에 Access-Control-Allow-Origin
를 추가해주었지만 프론트에서 받은 응답 헤더에는 없었고, 똑같이 CORS가 발생하여 차단되었다. 시간이 없는 관계로 프론트에서 프록시를 사용해서 우회하기로 하였다.
로컬에서는 번들러(Vite)에서 제공하는 server proxy 옵션을 사용하였다.
// vite.config.ts
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import * as path from 'path';
export default defineConfig({
plugins: [react()],
resolve: {
alias: [{ find: '@', replacement: path.resolve(__dirname, 'src') }],
},
server: {
proxy: {
// 문자열만 사용한다면 프록시를 거쳐 아래와 같이 변경된 주소로 요청된다.
'/api': // http://localhost:5173/api -> https://www.api.com/api
'https://www.api.com', // 백엔드 api 주소
},
},
});
const getImage = async (hobbyId: string): Promise<IHobbyData> => {
const data = await (await fetch(`/api/v1/hobbies/${hobbyId}`)).json();
// 위 요청은 http://localhost:5173/api/v1/hobbies/${hobbyId}
// -> https://www.api.com/api/v1/hobbies/${hobbyId} 로 요청된다.
return data;
};
vite.config.ts
에서 제공하는proxy
에는 다양한 옵션들이 있으며 링크를 통해 확인할 수 있다.
배포는 Netlify를 사용하였는데, Netlify에서는 제공하는 redirects 기능을 사용하여 proxy를 제공하고 있어서 해당 기능을 사용하였다.
netlify.toml
파일을 만들어 package.json
과 같은 디렉토리에 배치하였다. to
주소 끝 :splat
은 요청 시 남은 경로 및 쿼리스트링이 매칭되는 자리이다.
[[redirects]]
from = "/proxy/*"
to = "https://www.api.com/:splat"
status = 200
force = true
[[redirects]]
from = "/*"
to = "/index"
status = 200
import { PROXY } from '@/constants/proxyURL';
const getImage = async (hobbyId: string): Promise<IHobbyData> => {
const data = await (await fetch(`${PROXY}/api/v1/hobbies/${hobbyId}`)).json();
return data;
};
// proxyURL.ts
// netlify에서 설정한 프록시 주소로 환경에 따라 변경될 수 있게 추가한다.
export const PROXY = window.location.hostname === 'localhost' ? '' : '/proxy';
React를 사용한 SPA로 개발하였기 때문에 배포환경에서 경로가 변경되고 새로고침이 된다면
NotFound404
를 뿜어내게된다. netlify.toml 에서 규칙들은 순서를 가지며 "/proxy"를 우선시하고 매칭되는 주소가 없다면 아래 조건에 의해index.html
파일을 리턴하게 된다.
촉박한 상황에서 해당 문제를 해결하기 위해 최선의 선택은 아니었을 수 있지만 백엔드 분들과 협업하며 여러가지 배워갈 수 있었고, 프록시에 대해 공부할 수 있는 좋은 기회가 되었다. 아마 다음에 CORS 에러를 만난다고 해도 익숙하게 조치할 수 있을 것 같다.