웹 프로젝트를 진행하면서 CORS 정책 위반으로 에러가 발생했다.
이전 프로젝트를 진행할 때는 서버 담당자가 해결해 주었지만,
프로젝트를 React로 리뉴얼하는 과정에서 서버를 수정할 수 없었고 클라이언트에서 CORS 에러를 해결해야만 했다.
아직 100% 해결된 상태는 아니지만 CORS 에러에 대해 찾아보면서 적용했던 해결 방안을 정리해보려고 한다.
CORS 란?
Cross-Origin Resource Sharing의 줄임말로, 한국어로 직역하면 교차 출처 리소스 공유라고 할 수 있다.
개발자의 입장에서는 CORS 정책때문에 골치아플 수는 있지만, CORS에 의해 출처가 분명한 리소스만 제공받을 수 있다.
그렇다면 CORS에서 말하는 "출처"가 무엇인지 간단하게 알아보겠다.
출처(Origin) 란?
우리가 어떤 사이트에 접속하려면 사이트의 주소인 "URL"을 입력해서 접속하게 된다.
URL은 단순한 문자열이 아닌 아래와 같은 구성 요소로 이루어져 있다.
Protocol(Scheme) : http / https
Host : 사이트 도메인
Port : http - 80, https: 443 (기본 포트는 생략 가능)
Path : 사이트 내부 경로
Query String : 요청의 key, value 값
Fragment : 해시 태그
이때 출처란 URL의 Protocol, Host, Port를 합친 것을 의미한다.
CORS에 대해 더욱 자세히 알고 싶다면 아래의 자료를 참고하길 바란다.
참고 사이트
🌐 악명 높은 CORS 개념 & 해결법 - 정리 끝판왕 👏
악명 높은 CORS 에러 메세지 웹 개발을 하다보면 반드시 마주치는 멍멍 같은 에러가 바로 CORS 이다. 웹 개발의 신입 신고식이라고 할 정도로, CORS는 누구나 한 번 정도는 겪게 된다고 해도 과언이
inpa.tistory.com
해결 방법
1. Client : package.json의 proxy설정 및 http-proxy-middleware 라이브러리 사용
1-1. package.json 파일 안에 proxy 설정 추가
{
"browserslist": {
...
},
"proxy": "https://www.google.com"
}
1-2. http-proxy-middleware 라이브러리 설치
npm install http-proxy-middleware
yarn add http-proxy-middleware
1-3. src 폴더 내에 setupProxy.js 파일 생성 및 코드 작성
const { createProxyMiddleware } = require("http-proxy-middleware");
module.exports = function(app){
app.use("/api",
createProxyMiddleware({
target: "API 주소 작성",
changeOrigin: true,
pathRewrite: {
"^/api": "",
},
}),
);
};
1-4. API 통신 코드 작성
axios에서 호출하려는 path 앞에 "/api"를 붙여서 호출하면 CORS 에러 없이 데이터를 불러오는 것을 확인할 수 있다.
const getAPI = async () => {
const result = await axios.post(
"/api" + "호출 Path"
);
console.log(result);
}
하지만 이 방법은 개발 단계에서만 적용되는 방법이었고 프로젝트를 build한 후 배포했을 때 데이터를 받아오지 못했다.
2. Server : 간단한 Node 중계 서버 구현
2-1. express, cors 라이브러리 설치
npm i express cors
2-2. server 폴더 생성, app.js 파일 생성 및 코드 작성 (Node 서버)
const express = require('express');
const app = express();
const cors = require('cors');
const axios = require('axios');
const port = 3002;
const server_url = "API 서버 URL";
// cors 에러 처리
app.use(cors());
// API 호출 함수
const getAPI = async (req) => {
try {
const { data } = await axios.post(
`${server_url}/api/common`
)
return data;
} catch (err) {
console.log(err);
}
}
app.get("/api/common", (req, res) => {
getAPI(req).then((response) => {
res.json(response);
});
});
// 3002번 포트넘버를 가진 서버 생성
app.listen(port, () => console.log(`listening on port ${port}!`));
2-3. React의 App.ts에 중계 서버 호출 코드 작성
const App = () => {
const getAPI = async () => {
const result = await axios.get(
"http://localhost:3002/api/common"
);
console.log(result);
};
useEffect(() => {
getAPI();
), []};
};
export default App;
위의 코드를 실행시키면 Node 서버를 통해 data를 받아오게 되고 CORS 에러를 해결 할 수 있다.
하지만 이번 프로젝트에서 중계 서버를 사용하는 것은 의미가 없었고 다른 방법을 찾아봐야만 했다.
3. Client : 다른 사람이 만든 Proxy 서버 사용하기
proxy 서버로 "https://cors-anywhere.herokuapp.com/"가 있지만 403 forbidden 에러를 띄웠다.
해당 이슈를 찾아보니 사이트가 남용되고 있어서 사이트에 직접 방문해서 잠금을 해제 후 데모 버전으로 사용할 수 있다고 나왔다.
https://github.com/Rob--W/cors-anywhere/issues/301
PSA: Public demo server (cors-anywhere.herokuapp.com) will be very limited by January 2021, 31st · Issue #301 · Rob--W/cors-an
The demo server of CORS Anywhere (cors-anywhere.herokuapp.com) is meant to be a demo of this project. But abuse has become so common that the platform where the demo is hosted (Heroku) has asked me...
github.com
사이트로 들어가서 버튼을 눌러 데모 버전 잠금을 해제한 후 사용했고 API에서 데이터를 잘 받아왔다.
또 다른 proxy 서버인 "https://cors.bridged.cc/"서버를 사용해서 통신했고 데이터를 잘 받아오는 것을 확인했다.
3-1. API 호출 코드 작성
const getAPI = async () => {
const { data } = await axios.post(
"https://cors-anywhere.herokuapp.com/https://API 주소"
);
}
const getAPI = async () => {
const { data } = await axios.post(
"https://cors.bridged.cc/https://API 주소"
);
}
하지만 proxy 서버를 통해서 통신해서 그런지 응답이 매우 느렸고 배포되는 사이트에서는 사용할 수 없다고 판단했다.
서버를 고칠 수 없는 상황이 아니라면 서버를 고치는 방법이 제일 간단하고 좋은 방법인 것 같다.
'🖥️Frontend > React' 카테고리의 다른 글
[React] Redux & RTK (0) | 2023.11.17 |
---|---|
[React] xlsx & file-saver & csv (0) | 2023.09.14 |
[React] Inflearn 처음 만난 리엑트(React) - Context (0) | 2023.02.24 |
[React] Inflearn 처음 만난 리엑트(React) - Composition vs Inheritance (0) | 2023.02.24 |
[React] Inflearn 처음 만난 리엑트(React) - 조건부 렌더링 (0) | 2023.02.22 |
댓글