React
를 연동한 프로젝트를 진행하며 서비스를 배포하기로 결정하여 어떻게 배포할 지 고민하였다. 간편하게 배포만 하는 것이 목표였기 때문에 처음에는 Github Pages
를 이용하여 배포했다. 그런데 React
프로젝트 내에서 사용하는 공공데이터포털의 Open API가 http
프로토콜밖에 제공하지 않았고, Github Pages
는 https
를 enforce하기 때문에 Mixed Content
오류가 나와 데이터를 가져오지 못하는 이슈가 생겼다.
일반적으로 브라우저는 HTTPS
로 접속한 사이트에서 HTTP
통신을 통해 가져온 데이터를 사용하는 것을 허용하지 않는다. SSL
이 적용되지 않아 보안상 안전하지 않기 때문이다. 이 문제를 해결하기 위해 가비아 등의 사이트에서 도메인을 구입하여 Github Pages
에 custom domain을 적용하여 https
를 해제할 수도 있지만, client 단에서 HTTPS
를 적용하여 배포를 하고싶었다.
결론적으로 Node.js + Express
서버를 생성하여 문제 해결을 시도했다. React
에서는 Heroku
에서 배포한 HTTPS
프로토콜을 통해 서버로 fetch
요청을 하여 Mixed Content
이슈를 해결하고, 서버에서는 HTTP
통신을 통해 공공데이터포털에 데이터를 요청 및 가져온 후 client에 데이터를 보내주는 방식인 것이다. Heroku
에는 React
프로젝트를 빌드 및 배포하여 Express
가 빌드된 index.html
파일을 제공하도록 했다.
이 포스트를 읽으시는 분들께: 아래 예시 및 내용들이 정확하지 않을 수 있고, 보다 더 간편하고 효율적인 방법이 있을 수 있습니다. 오류가 있을 시 지적해주시면 감사드리겠습니다.
import express from 'express';
import cors from 'cors';
import path from 'path';
// ... body-parser, router 등 필요한 모듈 import
const PORT = process.env.PORT || 5000;
const corsOptions = {
// origin, credentials 등 필요한 경우 cors 옵션을 등록할 수 있다.
};
app.use(cors(corsOptions));
app.use(express.static(path.join(__dirname, '../build')));
app.get('/*', (req, res) => {
res.sendFile(paht.join(__dirname, '../build/index.html'));
});
app.listen(PORT, () => console.log(`listening on port ${PORT}`));
다른 출처에서 데이터나 파일을 요청하는게 아닌 이상 cors
등록이 필요하지 않다. path
를 위와 같이 지정하여 빌드된 React
프로젝트를 제공하도록 할 수 있다. 또한, Heroku
서버의 환경 변수에 의해 정해지는 포트 번호를 할당하기 위해 Node의 환경 변수 값을 담고 있는 process.env
를 이용하여 포트 번호를 지정할 수 있다.
Express
에서 공공데이터포털의 데이터는 axios
, xhr2
등의 라이브러리를 사용하면 간편하게 요청할 수 있다.
아래는 React
컴포넌트에서 fetch()
를 이용하여 Express
에 데이터를 요청하는 예시이다. Express
에 /data/person
이라는 라우팅이 지정되어 있다고 가정했다.
import { useEffect } from 'react';
const App = () => {
const FETCH_PATH = 'data/person';
const getData = async () => {
try {
const data = await (await fetch(FETCH_PATH)).json();
// data에 대한 처리 로직
} catch (error) {
console.log(error);
// 에러 처리 코드 추가
};
};
useEffect(() => {
getData();
}, []);
};
로컬 환경에서 프로젝트를 배포하려 한다면 프로젝트를 빌드한 후에 Heroku
에 푸시하여 배포를 진행할 수 있다. 먼저 Heroku에 가입하고, 터미널에서 로그인 및 헤로쿠 프로젝트를 생성한다.
heroku login
heroku create 프로젝트이름
root 단에 있는 package.json
파일 내 "scripts"
코드에 아래와 같이 추가하면 배포 준비가 완료된다.
"scripts": {
"start": "npm run dev:server",
"build": "react-scripts build",
"heroku-postbuild": "cd server && npm install",
"test": "react-scripts test",
"eject": "react-scripts eject",
"dev:server": "ts-node server/index.ts",
"dev:client": "react-scripts start"
},
기존 헤로쿠 서버에서는 Procfile
이라는 파일을 생성하여 명령어를 입력해주어야 서버가 실행되었지만, 최근에는 Procfile
이라는 파일이 없으면 npm start
명령으로 자동 실행된다.
참고: Procfile no longer required for Node.js apps
dev:server
와 dev:client
는 로컬 개발 환경에서 사용하고자 나눈 것이며, 실제 헤로쿠 서버에서는 dev:client
명령을 사용할 일은 없다. Express
가 빌드 파일을 제공하기 때문에 npm run dev:server
명령만 주어 서버만 실행시키면 된다.
server
폴더 내에 Express
를 구성하였기 때문에 ts-node server/index.ts
를 실행시켰다. 또한, heroku-postbuild
명령을 통해 server
폴더 내에 있는 npm 패키지들도 설치하도록 했다.
배포하기 전에 먼저 터미널에 npm run build
를 입력하여 프로젝트를 빌드한다. 그런 다음, github
레포지토리에 올리듯이 헤로쿠 프로젝트에 푸시한다.
git add .
git commit -m '커밋 메시지'
git push heroku main
푸시를 하면 배포 진행 상황을 알려주며, 헤로쿠 서버 내 로그는 아래 명령으로 확인할 수 있다.
heroku logs --tail
Heroku Dev Center
[HTTP] HTTPS 사용시 혼합 콘텐츠(Mixed Content) 및 안전하지 않은 콘텐츠에 대한 설명
Node.js 사이트 Heroku(헤로쿠)로 인터넷에 올리기