Express로 CORS 에러 해결하기
와 드디어... 해결... 프론트엔드에서 API를 이용하여 프로젝트를 만들다 보면 거의 반드시 CORS 에러를 마주하게 된다. 나는 서울시에서 제공하는 공공 API를 이용하여 프로젝트를 만들었는데 CORS 에러가 발생하였다. CORS 에러를 해결하는 방법을 구글에 검색하면 참 많은 방법이 나오는데, 그 중에서도 난 API만을 받아오는 작은 서버를 직접 만드는 방법을 선택하였다. CORS 에러는 원래 서버에서 해결해야 하는 에러이기 때문에 Node.js를 이용하여 해결하였다.
우선 유튜브 조코딩님의 https://youtu.be/Tt_tKhhhJqY 영상을 참고하였다. 기본적인 Node.js 내용을 이해할 수 있다. 이 내용을 바탕으로 API만을 위한 소소한 서버를 제작하고, CORS 에러를 해결해보자.
과정은 간단하다.
1. Node.js로 API 데이터 받아오기
2. Express의 CORS 라이브러리로 CORS 에러 없애주기
3. 2번 서버의 데이터를 프론트엔드에서 이용하기
Express는 Node.js의 프레임워크이다. Node.js를 만들어주고 난 뒤 Express를 설치해주면 된다. 우선, Node.js 프로젝트를 생성해주자. 그냥 자바스크립트 파일을 하나 만들어주면 된다. 그리고 npm init을 해서 package.json을 만든다. 그리고 express, axios, cors, dotenv를 npm으로 설치해주었다. dotenv는 환경변수를 사용할 때 쓰는 라이브러리로, 환경변수를 사용하지 않는다면 설치하지 않아도 된다.
// package.json
"dependencies": {
"axios": "^1.3.4",
"cors": "^2.8.5",
"dotenv": "^16.0.3",
"express": "^4.18.2"
}
// app.js
const express = require("express");
const axios = require("axios");
const cors = require("cors");
const app = express();
const port = 4000;
app.listen(port, () => console.log("running"));
port 번호는 임의로 설정하면 된다.
const express = require("express");
const axios = require("axios");
const cors = require("cors");
const app = express();
const port = 4000;
require("dotenv").config();
// API 주소 예시
const api_url = `http://openapi.seoul.go.kr:8088/${process.env.REACT_APP_API_KEY}/json/~`
const getAPI = async (request) => {
let response;
try {
response = await axios.get(api_url);
} catch (error) {
console.log(error);
}
return response;
};
app.get("/api", (req, res) => {
getAPI(req).then((response) => {
res.json(response.data);
});
});
app.listen(port);
그리고 이렇게 작성해주면 서버에서 API를 불러오는데 성공한다. 그러나 말 그대로 API 데이터만 불러왔을 뿐 아직 CORS 에러를 해결하지 않았다. CORS 에러는 CORS 라이브러리를 이용하여 다음과 같이 작성해준다.
const express = require("express");
const axios = require("axios");
const cors = require("cors");
const app = express();
const port = 4000;
require("dotenv").config();
app.use(cors());
const api_url = `http://openapi.seoul.go.kr:8088/${process.env.REACT_APP_API_KEY}/json/~`;
const getAPI = async (request) => {
let response;
try {
response = await axios.get(api_url);
} catch (error) {
console.log(error);
}
return response;
};
app.get("/api", (req, res) => {
getAPI(req).then((response) => {
res.json(response.data);
});
});
app.listen(port);
이렇게 app.use(cors())를 작성해주면 모든 출처에서 CORS가 허용된다. 특정 출처에서만 CORS를 허용하고 싶다면 추가적으로 입력해주어야 한다.
const express = require("express");
const axios = require("axios");
const cors = require("cors");
const app = express();
const port = 4000;
require("dotenv").config();
app.use(cors({ origin: "http://localhost:3000" }));
const api_url = `http://openapi.seoul.go.kr:8088/${process.env.REACT_APP_API_KEY}/json/~`;
const getAPI = async (request) => {
let response;
try {
response = await axios.get(api_url);
} catch (error) {
console.log(error);
}
return response;
};
app.get("/api", (req, res) => {
getAPI(req).then((response) => {
res.json(response.data);
});
});
app.listen(port);
프론트엔드 쪽의 origin을 작성해주었다. 이렇게 작성해주면 localhost:3000의 CORS가 허용된다.
프론트엔드 쪽의 코드를 살펴보자.
useEffect(() => {
async function getData() {
const response = await fetch("http://localhost:4000/api");
const result = await response.json();
}
getData();
}, []);
백엔드의 포트 번호를 4000으로 설정했고 /api에 대해 데이터를 받아오도록 작성했었으므로 localhost:4000/api의 주소를 입력해주면 CORS 에러가 해결된 API 데이터를 받을 수 있다.
그러나 주소를 localhost:4000으로 작성하면 local에서만 사용할 수 있다. 그렇다면 페이지를 온라인에 배포한 후에도 서버 주소를 사용하려면 어떻게 해야 할까? 서버 페이지도 배포하면 된다. 즉, 프론트엔드 페이지 따로, API 서버 페이지 따로 배포하여 프론트엔드 페이지가 서버 페이지(= CORS가 해결된 API 페이지)에서 데이터를 받아올 수 있게 하면 된다.
useEffect(() => {
async function getData() {
const response = await fetch("http://온라인으로 배포된 API 페이지");
const result = await response.json();
}
getData();
}, []);
이렇게 하면 local이 아닌 온라인에서도 API 데이터를 사용할 수 있다. Node.js를 온라인에 배포하는 방법은 다음 글에 작성하였다. https://inthedev.tistory.com/57
참고 자료
'FE - Tools > React' 카테고리의 다른 글
[React] Context API와 useReducer 사용법 알아보기 (0) | 2023.05.11 |
---|---|
[React] 제어 컴포넌트와 비제어 컴포넌트를 적절하게 사용하는 법 (0) | 2023.03.12 |
[React] React에서 네이버 지도 API 사용하기 (0) | 2023.01.19 |
[React] useParams 이용하기 (0) | 2022.12.22 |
[React] useEffect와 useLayoutEffect의 차이 (0) | 2022.12.20 |