์๋ฐ์คํฌ๋ฆฝํธ๋ ๋ธ๋ผ์ฐ์ ์์์ ๋์ํ๊ธฐ ์ํด ํ์ํ ์ธ์ด๋ค. ๋ธ๋ผ์ฐ์ ์ ์๋ฐ์คํฌ๋ฆฝํธ ์์ง์ด ์๋ฐ์คํฌ๋ฆฝํธ์ ๋ฐํ์์ด์์ง๋ง, NodeJS๊ฐ ํ์ํ๋ฉด์ ์๋ฐ์คํฌ๋ฆฝํธ๋ ๋๋ค๋ฅธ ํ๊ฒฝ์์ ์๋ํ ์ ์๊ฒ ๋์๋ค.
์ฆ NodeJS๋ ์๋ฐ์คํฌ๋ฆฝํธ์ ๋๋ค๋ฅธ ๋ฐํ์์ธ ์ ์ด๋ค(์๋ก์ด ์ธ์ด๊ฐ ์๋). ๋ธ๋ผ์ฐ์ ๊ฐ ์๋ ํ๊ฒฝ์์ ์๋ฐ์คํฌ๋ฆฝํธ ์ ํ๋ฆฌ์ผ์ด์ ์ด ์คํ๋๋ค๋ ๊ฒ ์ด๋ค ์๋ฏธ๊ฐ ์์๊น?
๊ฐ์ฅ ํฐ ์ด์ ๋ ํ์ต์ ๊ฑธ๋ฆฌ๋ ๋น์ฉ์ด๋ค. ์๋ฐ์คํฌ๋ฆฝํธ ํ๊ฒฝ์ด๊ธฐ ๋๋ฌธ์ ์น ๊ฐ๋ฐ์๋ค์ด ์๋ก์ด ์ธ์ด๋ฅผ ๋ฐฐ์ฐ์ง ์์๋ ๋๋ค๋ ์ฅ์ ์ด ์๋ค. ๋ํ ํ์ฌ ํฌ๋กฌ์์๋ ์ฌ์ฉ ์ค์ธ V8 ์์ง์ ์ฑํํ๊ธฐ ๋๋ฌธ์ ์๋์ ์ธ ์ธก๋ฉด์์๋ ๋ถ๋ฆฌํจ์ด ์ ๋ค.
๋ฎ์ ๋ฌ๋์ปค๋ธ์ ์ ์ ํ ์ฑ๋ฅ์ด ํ์ฌ NodeJS ์ฌ์ฉ๋์ ์ฆ๊ฐ์ํค๋๋ฐ ํฐ ์ญํ ์ ํ๋ค๊ณ ์๊ฐํ๋ค.
NodeJS ํ๊ฒฝ์์ ์๋ฐ์คํฌ๋ฆฝํธ๋ก ๊ตฌํํ ์ ํ๋ฆฌ์ผ์ด์ ์ ๊ตฌํํ ์ ์๋ค. ์ด ๋ง์ ์๋ฐ์คํฌ๋ฆฝํธ๋ก ๋ง๋ ์๋ฒ๋ฅผ ๊ตฌ์ถํ ์ ์๋ค๋ ๋ง๋ ํฌํจํ๋ค. ๋ชจ๋ ํ๊ฒฝ์ด ๊ทธ๋ ๋ฏ์ด ๋ฐ๋๋ผ ํ๊ฒฝ์์๋ ๋ฌด์ธ๊ฐ๋ฅผ ๋ง๋ค๊ธฐ ์ฝ์ง ์๋ค.
๊ทธ๋ ๊ธฐ ๋๋ฌธ์ ๋ฆฌ์กํธ, ๋ทฐ, ์ต๊ทค๋ฌ ๋ฑ ํ๋ก ํธ์๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ/ํ๋ ์์ํฌ ๋ฑ์ด ์๊ฒจ๋ฌ๊ณ ์ด๊ฒ์ ๋ฐฑ์๋์์๋ ๋ง์ฐฌ๊ฐ์ง๋ค. ๊ทธ ์ค ํ๋๊ฐ ExpressJS์ด๋ฉฐ ์ ์ธ๊ณ์ ์ผ๋ก ๋์ ์ ์ ์จ์ ๊ฐ์ง ๋ฐฑ์๋ ํ๋ ์์ํฌ ์ค ํ๋๋ค.
Express์ ๊ฐ์ฅ ํฐ ์ฅ์ ์ผ๋ก๋ ์์ฌ์ด ์ฌ์ฉ๋ฒ์ด ์๋ค. ๋ํ ์ ์ฐํ ๋ฏธ๋ค์จ์ด์ ์ถ๊ฐ๋ก ์ฌ์ฉ์๊ฐ ๋ค์ํ ๊ธฐ๋ฅ์ ํจ์จ์ ์ผ๋ก ์ถ๊ฐํ ์ ์๋ค๋ ์ ์ด ์๋ค. ๊ทธ๋ฆฌ๊ณ ๋์ ์ ์ ์จ์ ์ง๋ ๋งํผ ํฐ ๊ท๋ชจ์ ์ปค๋ฎค๋ํฐ๊ฐ ํ์ฑํ๋์ด ์๊ธฐ ๋๋ฌธ์ ์ด๊ฒ๋ ์ฅ์ ์ค ํ๋๋ค.
๋ค์ํ ๋ฏธ๋ค์จ์ด์ ์ถ๊ฐ๋ฅผ ํตํ ์ ์ฐํจ์ ์คํ๋ ค ๋จ์ ์ผ๋ก ์์ฉํ ์ ์๋ค. ๊ฑฐ๋ํ ๊ท๋ชจ์ ํ๋ก์ ํธ์์๋ ๋์ ์์ ๋๊ฐ ๋จ์ ์ผ๋ก ์์ฉํ ์ ์๋ค. Express๋ ๋น ๋ฅด๊ฒ ์๋ฒ๋ฅผ ๊ตฌ์ถํ๊ณ , ๋ฐฑ์๋์ ๊ธฐ์ด ์ง์์ด ํํํ์ง ๋ชปํ ์ฌ์ฉ์๊ฐ ์ฌ์ฉํ๊ธฐ์๋ ์ฝ๊ธฐ ๋๋ฌธ์ ๊ฐ๋จํ ์๋ฒ์ ์ ๋ฆฌํ ํ๋ ์์ํฌ์ด๋ค.
npm install express
npm install cors
์ฐ์ express ํจํค์ง๋ฅผ ์ค์นํด์ผํ๋ค. ์ง๊ธ ํ๊ฒฝ์์๋ ํ๋ก ํธ์๋๋ฅผ 5500 ํฌํธ๋ฅผ ๊ธฐ๋ณธ์ผ๋ก ์ฌ์ฉํ๋ live-server ์ต์คํ ์ ์ ์ฌ์ฉํ๊ณ , express๋ฅผ ์ด์ฉํ ๋ฐฑ์๋ ์๋ฒ๋ 8080 ํฌํธ๋ก ์ค์ ํ ๊ฒ์ด๊ธฐ ๋๋ฌธ์ cross-origin ํ๊ฒฝ์ด ๋๋ค.
CORS๋ฅผ ์ค์ ํด์ฃผ๊ธฐ ์ํด cors ํจํค์ง๋ ํจ๊ป ์ค์นํ๋ค. ๊ทธ๋ฆฌ๊ณ ESmodule ์์คํ ์ ์ฌ์ฉํ๊ธฐ ์ํด package.json์ type์ module๋ก ์ค์ ํ๋ค.
import express from 'express';
import cors from 'cors';
import api from './api/index.js';
const app = express();
const port = 8080;
app.use(cors({ origin: 'http://127.0.0.1:5500', credentials: true }));
app.use(express.json());
app.use(cookieMiddleware);
app.use('/api', api);
app.listen(port, () => {
console.log('app is listening on port ' + port);
});
๊ฐ๋จํ ์๋ฒ๋ฅผ ์คํ์ํค๋ ์ฝ๋์ด๋ค. use๋ ๋ฏธ๋ค์จ์ด ์ค์ , listen์ ๊ณต์๋ฌธ์์ ๋ฐ๋ฅด๋ฉด Node์ http.Server.listen() ๋ฉ์๋์ identical์ด๋ผ๊ณ ํ๋ค.
๋ฏธ๋ค์จ์ด๋ ์ปดํจํฐ ๊ณตํ์์ ๋์ ๋ป์ ๊ฐ์ง๊ณ ์์ง๋ง ์ฝ๊ฒ ํํํ์๋ฉด ๊ณผ์ ์ ์ค๊ฐ์์ ํน์ ํ ์์ ์ ์ํํด์ฃผ๋ ์ญํ ์ ํ๋ ํ๋์จ์ด ๋๋ ์ํํธ์จ์ด์ด๋ค.
ํ์ฌ ์ฝ๋์ ๋ฐ๋ฅด๋ฉด app์ด๋ผ๋ ์ด๋ฆ์ผ๋ก ์ ์ธ๋ express ์ฑ์ด 3๊ฐ์ ๋ฏธ๋ค์จ์ด๋ฅผ ์ฌ์ฉํ๊ณ ์๋ค. Express ๋ฏธ๋ค์จ์ด๋ ํฌ๊ฒ 3๊ฐ์ง๋ก ๋ถ๋ฅํ ์ ์๋๋ฐ, ์ฒซ ๋ฒ์งธ๋ ๋ชจ๋ ์์ฒญ์ ๋ํด ํน์ ๊ธฐ๋ฅ์ ์ํํ๋ ๋ฏธ๋ค์จ์ด, ๋ ๋ฒ์งธ๋ ํน์ ๊ฒฝ๋ก์ ๋ํด์๋ง ์์ ์ ์ํํ๋ path ๋ฏธ๋ค์จ์ด, ๋ง์ง๋ง์ผ๋ก err๋ฅผ ํธ๋ค๋งํ๋ ๋ฏธ๋ค์จ์ด์ด๋ค.
์์ ์์์์๋ ์ฒซ ๋ฒ์งธ ํํ์ ๋ฏธ๋ค์จ์ด์ api ๊ฒฝ๋ก๋ก ๋ค์ด์ค๋ ์์ฒญ์ ์ฒ๋ฆฌํ๋ path ๋ฏธ๋ค์จ์ด๋ฅผ ์ฌ์ฉํ๊ณ ์๋ค.
cors๋ ํฌ๋ก์ค ์ค๋ฆฌ์ง ์ค์ ์ ์ํ ๋ฏธ๋ค์จ์ด, express.json()์ ์์ฒญ์ Content-Type ํค๋๋ฅผ ํ์ธํด json ํํ๋ก ๋ค์ด์ค๋ ํ์ด๋ก๋๋ค์ ํ์ฑํด์ค๋ค. ๊ธฐ๋ณธ์ ์ผ๋ก body-parser ๋ชจ๋์ ๊ธฐ๋ฐ์ผ๋ก ํ๊ณ ์๋ค.
cookieMiddleware๋ ๋ฐ๋ก ๊ตฌํํ ๊ฒ์ธ๋ฐ, request์ ํค๋์ ์๋ ์ฟ ํค string์ ์กฐํํด ๊ฐ์ฒด ํํ๋ก request์ cookies๋ผ๋ ์ด๋ฆ์ผ๋ก ์ถ๊ฐํด์ค๋ค.
์ฌ์ค ๊ฐ์ ์์ ์ ํด์ฃผ๋ cookieParser๋ผ๋ ๋ฏธ๋ค์จ์ด๊ฐ ์กด์ฌํ์ง๋ง ๊ทธ๋ฅ ๊ตฌํํด๋ดค๋ค.
์ด๋ฒ ํํ ๋ฆฌ์ผ์์๋ ํด๋ผ์ด์ธํธ์์ api ๊ฒฝ๋ก๋ก ๋ณด๋ธ ์์ฒญ๋ค์ ๋ค๋ฅธ ๋ผ์ฐํฐ์์ ์ฒ๋ฆฌํ๋ ๊ฒ์ผ๋ก ๊ตฌํํ๋ค. ์์ ์ค๋ช ํ๋๋๋ก api path๋ฅผ ์ฒ๋ฆฌํ๋ ๋ฏธ๋ค์จ์ด๊ฐ ํ์ํ๋ฐ, ๊ตฌํ์ ๋ค์๊ณผ ๊ฐ๋ค.
// /api/index.js
import { Router } from 'express';
import sessionMiddleware from '../middleware/sessionMiddleware.js';
import auth from './auth/index.js';
import board from './board/index.js';
const router = Router();
router.use('/auth', sessionMiddleware, auth);
router.use('/board', board);
export default router;
A router object is an isolated instance of middleware and routes
๋ผ์ฐํฐ๋ ๋ฏธ๋ค์จ์ด์ฒ๋ผ ๋์ํ๊ธฐ ๋๋ฌธ์ use ๋ฉ์๋๋ฅผ ํตํด ๋ฑ๋กํ ์ ์๋ค. ์์ ์์์์ ๋ณด์ด๋ ๊ฒ์ฒ๋ผ ์๋ก์ด ๋ผ์ฐํฐ ์ค๋ธ์ ํธ๋ฅผ ๋ง๋ค๊ณ , ๊ทธ๊ฒ์์ ๋๋ค๋ฅธ ๋ผ์ฐํฐ๋ฅผ ๋ฑ๋กํ๋ ๊ฒ๋ ๊ฐ๋ฅํ๋ค.
ํ์ฌ ์ฝ๋์์๋ api ๋ผ์ฐํฐ๊ฐ auth, board ๋ผ์ฐํฐ๋ฅผ ๊ฐ๊ฐ์ ๊ฒฝ๋ก์ ์ฐ๊ฒฐํ๊ณ ์๋ค.
// api/auth/index.js
import { Router } from 'express';
const router = Router();
router.post('/login', (req, res) => {
res.status(200).json({ text: '์๋
ํ์ธ์!' });
});
export default router;
auth ๋ผ์ฐํฐ์์ login ๊ฒฝ๋ก๋ก ๋ค์ด์ค๋ POST ์์ฒญ์ ์ฒ๋ฆฌํ๋ callback์ ๋ฑ๋กํ๋ค. response ๊ฐ์ฒด์ status ์ฝ๋์ json ํํ๋ก ๋ฐ์ดํฐ๋ฅผ ์ ๋ฌํ๋ค.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<script src="./index.js" defer></script>
<link rel="stylesheet" href="./style.css" />
<title>Document</title>
</head>
<body>
<h1>Title</h1>
<div>
<button class="login">login</button>
</div>
</body>
</html>
async function login() {
const response = await fetch('http://localhost:8080/api/auth/login', {
method: 'POST',
credentials: 'include',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
userId: 'lee',
password: '1234',
}),
}).then((res) => {
return res.json();
});
console.log(response);
}
(function () {
const loginBtn = document.querySelector('.login');
loginBtn.addEventListener('click', login);
})();
ํ๋ก ํธ์๋์์๋ ๋ก๊ทธ์ธ ๋ฒํผ์ ํด๋ฆญ ์ ์ต์คํ๋ ์ค ์ฑ์ ์ค์ ํ ๊ฒฝ๋ก์ธ api/auth/login์ผ๋ก POST ์์ฒญ์ ๋ณด๋ด๋๋ก ํ๋ค. ํ์ฌ ์ฑ์์ 8080 ํฌํธ๋ก ์๋ฒ๋ฅผ ์ด์๊ธฐ ๋๋ฌธ์ localhost:8080์ด ๋ฒ ์ด์ค ์ฃผ์๊ฐ ๋๋ค.
ํ๋ก ํธ์๋์ ์คํ์ live server ์ต์คํ ์ , ๋ฐฑ์๋์ ์คํ์ node ๋ช ๋ น์ด๋ก ํ๋ค.
ํ๋ก์ ํธ์ ๊ตฌ์กฐ๋ ๋ค์๊ณผ ๊ฐ๋ค.
node src/app
๋ค์ ๋ช ๋ น์ด๋ก ์๋ฒ๋ฅผ ์คํ์ํค๊ณ live server ๊ฐ๋ ๋ช ๋ น์ด๋ก ํ๋ก ํธ์๋ ์๋ฒ๋ฅผ ์คํ์ํจ๋ค.
๊ฐ๋ฐ์ ๋๊ตฌ๋ฅผ ํตํด ๋ฒํผ์ ํด๋ฆญํ๋ฉด ๋ค์๊ณผ ๊ฐ์ ์ถ๋ ฅ์ ๋ณผ ์ ์๋ค. ๐
๋ค์ ํํ ๋ฆฌ์ผ์์๋ ์๋ฒ์์ set-cookie๋ฅผ ํ๋ ๋ฒ์ ๋ํด ํฌ์คํ ํ ์์ ์ด๋ค ใ ใ .