React - Node.js & React - Spring CORS 해결방법(1)
보통 웹개발을 할 때, React로 프론트앤드를 개발하고 Node.js나 Spring 등을 이용해 백앤드를 개발하여 둘을 연결시켜서 개발하게 되는데요.
이 때 프론트앤드와 백앤드가 사용하는 Port가 다르다보니 서로 Ajax 등을 이용해 통신을 할 때 CORS 정책 위반이 에러로 뜨면서 데이터를 주고 받을 수 없는 상황이 벌어집니다.
우선 CORS 정책이 무엇인지 알아볼까요?
교차 출처 리소스 공유 (CORS)
보안 상의 이유로, 브라우저는 스크립트에서 시작한 교차 출처 HTTP 요청을 제한합니다. CORS 체제는 브라우저와 서버 간의 안전한 교차 출처 요청 및 데이터 전송을 지원합니다.
CORS 정책의 정의는 위와 같이 기술되어 있는데요. 쉽게 말해서 보안 상의 이유로 Port 번호가 다른 웹페이지에서 정보를 요청할 시 해당 요청을 브라우저가 임의로 막아버리는 것입니다. 이를 해결하기 위해서는 프론트앤드인 React에서 Proxy 등을 이용해 CORS정책을 우회할 수 있고 백앤드인 Node.js나 Spring에서 해결할 수도 있는데요. 이번에는 Node.js나 Spring에서 어떻게 CORS정책을 해결할 수 있는지 알아보겠습니다.
1. Node.js
Node.js 에서 React로 보내고자하는 정보를 가지고 있는 파일을 NewsData.js파일로 만들고( 이 때 제가 보낼 정보는 News 관련된 Data라서 이름을 이렇게 지었습니다.) 이를 express를 이용해 server를 가동시킬 server.js 파일을 분리하였습니다.
(1) server.js
const express = require('express');
const cors = require('cors');
const api = require('./routes/NewsData');
const app = express();
app.use(express.static(__dirname));
app.use(
cors({
origin: true,
credentials: true,
}),
);
app.use('/api', api);
const port = 3002;
app.listen(port, ()=>{
console.log(`express is running on ${port}`);
})
Node.js에서 server를 가동시킬 express와 CORS 정책을 해결할 cors 그리고 보낼 정보를 가지고 있는 NewsData파일(경로는 해당 파일이 있는 곳으로 지정해주시면 됩니다.) 을 require해서 가져오고, app.use(cors({...})) 이 부분에서 origin과 credentials를 true 값을 주시면 CORS 정책을 해결할 수 있습니다. 이후 'localhost:3002/api'로 요청이 들어오면 NewsData를 실행시키기 위해 port번호는 3002번으로 listening하게 하였고 app.use('api', api)로 '/api'로 요청이 들어오면 api(NewsData를 가져온 변수) 를 실행시키도록 하였습니다.
(2) NewsData.js
var express = require('express');
var router = express.Router();
router.get('/', function(req, res){
let DATA = ... // 보낼 데이터를 입력하시면 됩니다.
res.send({'DATA':DATA}); // JSON형식으로 보내도록 하였습니다.
});
module.exports = router;
실제 데이터를 보낼 NewsData.js에서는 router를 이용해 요청이 들어왔을 때 function()을 실행시켜 data를 res.send를 통해 데이터를 보낼 수 있습니다.
(3) React
import React, { useState, useEffect } from 'react';
import axios from "axios"; // axios를 이용해 server와 통신합니다.
//backend의 데이터 불러오기
var url = "http://localhost:3002/api";
axios.defaults.withCredentials = true;
useEffect(() => {
axios.get(url)
.then((response) => {
for(let i = 0; i < response.data.newsPages; i++) {
NewsList1.push({
no : i,
title : response.data.newsBoardContent[i],
url : response.data.newsBoardHref[i],
image : response.data.newsBoardImgae[i],
set : true,
})
}
setDataList(NewsList1);
setOriginalData(NewsList1);
});
}, []);
프론트앤드 쪽 React 코드는 제가 했던 프로젝트에서 일부 발췌한거라 실제로 적용하실 때에는 response.data의 속성이나 useState의 set부분이 다를 수 있으므로 각 상황에 맞게 수정하시면 됩니다. 프론트앤드에서는 CORS정책을 해결하기 위해 axios.defaults.withCredentials = true; 한 줄만 작성하시면 나머지는 백앤드에서 처리하기 때문에 프론트앤드에서 거의 건드릴 부분이 없습니다! 나머지 부분은 axios에서 url로 get 요청을 보내고 나서 응답을 받으면 response 변수에 저장하고 해당 변수를 이용해 원하는 부분을 set하는 코드입니다.
이상으로 Node.js 와 React 간의 서버통신 시 발생할 수 있는 CORS 보안 위반 문제를 어떻게 해결하는 지를 보았습니다. 다음 게시글에서는 2편으로 Spring과 React 간의 서버통신 시 발생할 수 있는 CORS 보안 위반 문제를 어떻게 해결하는지를 살펴보겠습니다.