node.js(4) - Express.js ์์ํ๊ธฐ
๐ฅ express ์์ํ๊ธฐ
โ ๋ช ๋ น์ด ์ ๋ ฅํ๊ธฐ
$ npm i express
$ npm i -D nodemon
โ package.json์ scripts ์์ ํ๊ธฐ
"name": "learn-express",
"version": "0.0.1",
"description": "์ต์คํ๋ ์ค๋ฅผ ๋ฐฐ์ฐ์",
"main": "app.js",
"scripts": {
"start": "nodemon app"
},
"author": "ZeroCho",
"license": "MIT"
}
start ์์ฑ : nodemon app์ ํ๋ฉด app.js๋ฅผ nodemon์ผ๋ก ์คํํจ
app.js
- ์๋ฒ๊ฐ ๋จ
const express= require('express');
const app = express();
app.set('port', process.env.PORT || 3000);
app.get('/', (req,res) => {
res.send('Hello, Express');
});
app.listen(app.get('port'), ()=>{
console.log(app.get('port', '๋ฒ ํฌํธ์์ ๋๊ธฐ ์ค'));
});
express ๋ชจ๋ ์์ http ๋ชจ๋์ด ๋ด์ฅ๋์ด ์์ผ๋ฏ๋ก ์๋ฒ์ ์ญํ ์ ํด์ค๋ค.
app.set('port', ํฌํธ)
- ์๋ฒ๊ฐ ์คํ๋ ํฌํธ๋ฅผ ์ค์ ํจ
- process.env ๊ฐ์ฒด์ PORT ์์ฑ์ด ์๋ค๋ฉด ๊ทธ ๊ฐ์ ์ฌ์ฉํ๊ณ , ์๋ค๋ฉด ๊ธฐ๋ณธ๊ฐ์ผ๋ก 3000๋ฒ ํฌํธ๋ฅผ ์ด์ฉํ๊ฒ ํ๋ค.
app.get('์ฃผ์', ๋ผ์ฐํฐ)
- ์ฃผ์์ ๋ํ GET ์์ฒญ์ด ์ฌ ๋ ์ด๋ค ๋์์ ํ ์ง ์ ๋ ๋ถ๋ถ
- req : ์์ฒญ์ ๊ดํ ์ ๋ณด๊ฐ ๋ค์ด ์๋ ๊ฐ์ฒด
- res : ์๋ต์ ๊ดํ ์ ๋ณด๊ฐ ๋ค์ด ์๋ ๊ฐ์ฒด
- ์ฌ๊ธฐ์๋ GET / ์์ฒญ ์ ์๋ต์ผ๋ก Hello, Express๋ฅผ ์ ์ก
๊ฐ์ ์๋ฏธ๋ก app.post, app.put, app.patch. app.delete, app.options ๋ฉ์๋๊ฐ ์์
res.Sendfile(__dirname, '์๋ต์ผ๋ก ํด๋ผ์ด์ธํธ์๊ฒ ํ๊ณ ์ถ์ html ํ์ผ ์ด๋ฆ')
- HTMLํ์ผ๋ก ์๋ตํ๊ธฐ ์ํ ๋ฉ์๋
- ํ์ผ์ ๊ฒฝ๋ก๋ฅผ path ๋ชจ๋์ ์ฌ์ฉํ์ฌ ์ง์ ํด์ผ ํจ
index.html
<html>
<head>
<meta charset="UTF-8" />
<title>์ต์คํ๋ ์ค ์๋ฒ</title>
</head>
<body>
<h1>์ต์คํ๋ ์ค</h1>
<p>๋ฐฐ์๋ด
์๋ค.</p>
</body>
</html>
app.js
const express = require('express');
const path = require('path');
const app = express();
app.set('port', process.env.PORT || 3000);
app.get('/', (req, res) => {
// res.send('Hello, Express');
res.sendFile(path.join(__dirname, '/index.html'));
});
app.listen(app.get('port'), () => {
console.log(app.get('port'), '๋ฒ ํฌํธ์์ ๋๊ธฐ ์ค');
});
๋ฏธ๋ค์จ์ด
- ์์ฒญ๊ณผ ์๋ต์ ์ค๊ฐ(middle)์ ์์นํจ
- ๋ผ์ฐํฐ, ์๋ฌ ํธ๋ค๋ฌ๋ฅผ ๊ฐ๋ฅดํด
- ์์ฒญ๊ณผ ์๋ต์ ์กฐ์ํด ๊ธฐ๋ฅ์ ์ถ๊ฐํ๊ธฐ๋ ํ๊ณ , ๋์ ์์ฒญ์ ๊ฑธ๋ฌ๋ด๊ธฐ๋ ํจ
- app.use(๋ฏธ๋ค์จ์ด) ํํ๋ก ์ฌ์ฉ๋๋ค.
- ์์์๋ถํฐ ์๋๋ก ์์๋๋ก ์คํ๋๋ฉด์ ์์ฒญ๊ณผ ์๋ต ์ฌ์ด์ ํน๋ณํ ๊ธฐ๋ฅ์ ์ถ๊ฐํ๋ ๊ฒ๋ ๊ฐ๋ฅํจ
โ app.js
- ์๋ฒ์ ๋ฏธ๋ค์จ์ด ์ฐ๊ฒฐํ๊ธฐ
const express= require('express');
const app = express();
app.set('port', process.env.PORT || 3000);
app.use((req, res, next) => {
console.log('๋ชจ๋ ์์ฒญ์ ๋ค ์คํ๋ฉ๋๋ค.');
next();
});
app.get('/', (req, res, next)=>{
console.log('GET / ์์ฒญ์์๋ง ์คํ๋ฉ๋๋ค.');
next();
}, (req, res)=>{
throw new Error('์๋ฌ๋ ์๋ฌ ์ฒ๋ฆฌ ๋ฏธ๋ค์จ์ด๋ก ๊ฐ๋๋ค.')
});
app.use((err, req, res, next) => {
console.error(err);
res.status(500).send(err.message);
});
app.listen(app.get('port'), ()=>{
console.log(app.get('port', '๋ฒ ํฌํธ์์ ๋๊ธฐ ์ค'));
})
next() ํจ์
app.use((req, res, next) => {
//์คํ ํจ์
next();
- ๋ค์ ๋ฏธ๋ค์จ์ด๋ก ๋์ด๊ฐ๋ ํจ์
- next๊ฐ ์คํ๋์ง ์์ผ๋ฉด ๋ค์ ๋ฏธ๋ค์จ์ด๊ฐ ์คํ๋์ง ์๋๋ค.
- app.use, app.get์ ํ๋ผ๋ฏธํฐ๊ฐ ๋ ์ ์๋ค.
๋ฏธ๋ค์จ์ด๊ฐ ์คํ๋๋ ๊ฒฝ์ฐ
- app.use๋ app.get ๊ฐ์ ๋ผ์ฐํฐ์ ๋ฏธ๋ค์จ์ด๋ฅผ ์ฌ๋ฌ ๊ฐ ์ฅ์ฐฉํ ์ ์๊ฒ ํ ์ ์๋ค.
- ์ฃผ์๋ฅผ ์ฒซ ๋ฒ์งธ ์ธ์๋ก ๋ฃ์ด์ฃผ์ง ์๋๋ค๋ฉด ๋ฏธ๋ค ์จ์ด๋ ๋ชจ๋ ์์ฒญ์์ ์คํ๋๊ณ , ์ฃผ์๋ฅผ ๋ฃ๋ ๋ค๋ฉด ํด๋นํ๋ ์์ฒญ์์๋ง ์คํ๋๋ค.
๐ ์๋ฌ ์ฒ๋ฆฌ ๋ฏธ๋ค์จ์ด
app.use((err, req, res, next) => {
console.error(err);
res.status(500).send(err.message);
});
- ๋งค๊ฐ๋ณ์๊ฐ err, req, res, next๋ก ๋ค ๊ฐ๊ฐ ๋ฐ๋์ ๋ค์ด๊ฐ์ผ ํ๋ค.
- err์๋ ์๋ฌ์ ๊ดํ ์ ๋ณด๊ฐ ๋ด๊ฒจ ์๊ฒ ๋๋ค.
โ morgan, cookie-parser, express-session, dotenv ์ค์นํ๊ธฐ
npm i morgan cookie-parser express-session dotenv
๐ dotenv
- process.env๋ฅผ ๊ด๋ฆฌํ๊ธฐ ์ํ ํจํค์ง
- .env ํ์ผ์ ๋ง๋ค์ด์ฃผ์ด์ผ ํ๋ค.
app.js
//์ค์นํ ํจํค์ง๋ค์ธ morgan, cookie-parser, express-session(session) dotenv, express, path ๋ชจ๋ ๋ถ๋ฌ์ด
const express = require('express');
const morgan = require('morgan');
const cookieParser = require('cookie-parser');
const session = require('express-session');
const dotenv = require('dotenv');
const path = require('path');
//ํ๊ฒฝ์ค์ ์ ์ฉ : dotenv.config()
dotenv.config();
//const app = express(์๋ฒ๋ฅผ app์ผ๋ก, ์๋ฒ๋ express๋ก ๊ตฌ์ถํจ)
const app = express();
//app.set( ) : ํฌํธ ์ฐ๊ฒฐ
//process.env : ๋ณด์๊ณผ ์ค์ ์ ํธ์์ฑ , .env์ ๋น๋ฐ ํค๋ฅผ ์ ์ด๋๊ณ dotenv ํจํค์ง๋ก ๋น๋ฐ ํค๋ฅผ ๋ก๋ฉํด์ค๋ค.
app.set('port', process.env.PORT || 3000);
//์์์ ์ค์นํ ํจํค์ง๋ค์ app.use ๋ฏธ๋ค์จ์ด๋ก ์ฐ๊ฒฐํ๋ค.
//morgan ๋ฏธ๋ค์จ์ด ์ฌ์ฉํ๊ธฐ
app.use(morgan('dev'));
//static ๋ฏธ๋ค์จ์ด ์ฌ์ฉํ๊ธฐ
app.use('/', express.static(path.join(__dirname, 'public')));
//body-parser ๋ฏธ๋ค์จ์ด ์ฌ์ฉํ๊ธฐ
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
//cookie-parser ๋ฏธ๋ค์จ์ด ์ฌ์ฉํ๊ธฐ
app.use(cookieParser(process.env.COOKIE_SECRET));
// express-session ๋ฏธ๋ค์จ์ด ์ฌ์ฉํ๊ธฐ
app.use(session({
resave: false,
saveUninitialized: false,
secret: process.env.COOKIE_SECRET,
cookie: {
httpOnly: true,
secure: false,
},
name: 'session-cookie',
}));
app.use((req, res, next) => {
console.log('๋ชจ๋ ์์ฒญ์ ๋ค ์คํ๋ฉ๋๋ค.');
next();
});
์์ app.use๊ฐ ๊ณ์ ์ค๋ณต์ฌ์ฉํ๋ ๊ฒ์ด ๋ณ๋ก ์ด์์ง ์์์, ๋์์ ์ฌ๋ฌ ๋ฏธ๋ค์จ์ด๋ฅผ ํ๋๋ก ๋ฌถ์ด์ ์์ฑํด์ฃผ์
app.use(
morgan('dev'),
express.static('/', path.join(__dirname, 'public')),
express.json(),
express.urlencoded({ extended: false }),
cookieParser(process.env.COOKIE_SECRET),
);
๐ morgan ๋ฏธ๋ค์จ์ด
- ์ธ์๋ก dev ์ธ์ combined, common, short, tiny ๋ฑ์ ๋ฃ์ ์ ์๋ค.
- ๊ฐ๋ฐ ํ๊ฒฝ์์๋ dev๋ฅผ, ๋ฐฐํฌ ํ๊ฒฝ์์๋ combined์ ์ฌ์ฉํ๋ค.
app.use(morgan('dev'));
์์ ์ฝ๋๋ฅผ ์ฝ์ ์ฐฝ์ ์ฐ์ด๋ณด๋ฉด,
์์ ๋งจ๋ง์ง๋ง์ GET / 500 7.409 ms - 50 ๋ก๊ทธ๋ ๋ฏธ๋ค์จ์ด์์ ๋์ค๋ ๊ฒ์ด๋ค.
- [HTTP ๋ฉ์๋] [์ฃผ์] [HTTP ์ํ ์ฝ๋] [์๋ต ์๋] - [์๋ต ๋ฐ์ดํธ]๋ฅผ ์๋ฏธํจ
๐ static ๋ฏธ๋ค์จ์ด
- ์ ์ ์ธ ํ์ผ๋ค์ ์ ๊ณตํ๋ ๋ผ์ฐํฐ
- ๊ธฐ๋ณธ์ ์ผ๋ก ์ ๊ณต๋๊ธฐ์ ๋ฐ๋ก ์ค์นํ ํ์ ์์ด express ๊ฐ์ฒด ์์์ ๊บผ๋ด ์ฅ์ฐฉํ๋ฉด ๋จ
static ๋ฏธ๋ค์จ์ด ํํ
app.use('์์ฒญ ๊ฒฝ๋ก', express.static('์ค์ ๊ฒฝ๋ก'));
app.use('/', express.static(path.join(__dirname, 'public')));
- public : ์ค์ ์๋ฒ์ ํด๋ ๊ฒฝ๋ก
- ์์ฒญ์ฃผ์์๋ public์ด ๋ค์ด ์์ง ์๊ธฐ ๋๋ฌด๋ค ์๋ฒ์ ํด๋ ๊ฒฝ๋ก์ ์์ฒญ ๊ฒฝ๋ก๊ฐ ๋ค๋ฅด๋ฏ๋ก, ๋ณด์์ ์ธก๋ช ๊ฐํ
- ์์ฒญ ๊ฒฝ๋ก์ ํด๋น๋๋ ํ์ผ์ด ์์ผ๋ฉด ๋ด๋ถ์ ์ผ๋ก next๋ฅผ ํธ์ถํ๊ณ , ๋ง์ฝ ํ์ผ์ด ์กด์ฌํ๋ค๋ฉด ๋ค์ ๋ฏธ๋ค์จ์ด๋ ์คํ๋๋ค.(์๋ต์ผ๋ก ํ์ผ์ ๋ณด๋ด๊ณ next๋ฅผ ํธ์ถํ์ง ์๊ธฐ ๋๋ฌธ)
body-parser ๋ฏธ๋ค์จ์ด ์ฌ์ฉํ๊ธฐ
- ์์ฒญ์ ๋ณธ๋ฌธ์ ์๋ ๋ฐ์ดํฐ๋ฅผ ํด์ํด์ req.body ๊ฐ์ฒด๋ก ๋ง๋ค์ด์ค๋ค.
- ํผ ๋ฐ์ดํฐ๋ AJAX ์์ฒญ์ ๋ฐ์ดํฐ๋ฅผ ์ฒ๋ฆฌํจ
- ๋ฉํฐํํธ(์ด๋ฏธ์ง, ๋์์, ํ์ผ) ๋ฐ์ดํฐ ์ฒ๋ฆฌ๋ ๋ถ๊ฐ๋ฅํจ
- JSON๊ณผ URL-encoded ํ์์ ๋ฐ์ดํฐ ์ธ์๋ Raw, Text ํ์์ ๋ฐ์ดํฐ ์ญ์ ํด์ํ๋ ๊ฒ์ด ๊ฐ๋ฅํ๋ค.
โ ์ค์น ๋ช ๋ น์ด
$ npm i body-parser
- body-parser๊ฐ ๋ด์ฅ๋์ด์์ ๋๋ ์ธ ํ์ ์์ง๋ง npm์ ๋ค์ด๊ฐ ์์ง ์์ ๋ฐ๋ก ์ค์น๊ฐ ๋์ด ์์ง ์์ผ๋ฉด ๋ค์์ app.js์ ์ถ๊ฐํด์ฃผ์ด์ผ ์ฌ์ฉ์ด ๊ฐ๋ฅํ๋ค.
const bodyParser = require('body-parser');
app.use(bodyParser.raw());
app.use(bodyParser.text());
๐ body-parser ๋ฏธ๋ค์จ์ด ํํ
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
๐ง express.json
- JSON ํ์์ ๋ฐ์ดํฐ ์ ๋ฌ ๋ฐฉ์
- JSON ํ์์ ๋ฐ์ดํฐ์ธ { name: 'zerocho', book: 'nodejs' }๋ฅผ ๋ณธ๋ฌธ์ผ๋ก ๋ณด๋ธ๋ค๋ฉด req.body์ ๊ทธ๋๋ก ๋ค์ด๊ฐ๊ฒ ๋๋ค.
๐ง express.urlencoded
- ์ฃผ์ ํ์์ผ๋ก ๋ฐ์ดํฐ๋ฅผ ๋ณด๋ด๋ ๋ฐฉ์
๐ง express.urlencoded({ extended: false })
- false์ด๋ฉด ๋ ธ๋์ querystring ๋ชจ๋์ ์ฌ์ฉํด ์ฟผ๋ฆฌ์คํธ๋ง์ ํด์ํ๊ณ , true์ด๋ฉด qs ๋ชจ๋์ ์ฌ์ฉํด ์ฟผ๋ฆฌ์คํธ๋ง์ ํด์ํ๋ค.
- URL-encoded ํ์์ผ๋ก name=zerocho&book=nodejs๋ฅผ ๋ณธ๋ฌธ์ผ๋ก ๋ณด๋ธ๋ค๋ฉด req.body์ { name: 'zerocho', book: 'nodejs' }๊ฐ ๋ค์ด๊ฐ๋ค.
๐ qs ๋ชจ๋
- ๋ด์ฅ ๋ชจ๋์ด ์๋๋ผ npm ํจํค์ง์
- querystring์ ๋ ํ์ฅํ ๊ฒ
- ์ค์น ๋ฐฉ๋ฒ
npm i install qs
๐ cookie-parser์ ๋ฏธ๋ค์จ์ด
- ๋๋ด๋ ์ฟ ํค๋ฅผ ํด์ํด req.cookies ๊ฐ์ฒด๋ก ๋ฐ๊ฟ
cookie-parser ๋ฏธ๋ค์จ์ด ํํ
app.use(cookieParser(๋น๋ฐ ํค));
app.use(cookieParser(process.env.COOKIE_SECRET));
- name=zerocho ์ฟ ํค๋ฅผ ๋ณด๋๋ค๋ฉด req.cookies๋ { name: 'zerocho' }์
- ์๋ช ์ด ๋ถ์ผ๋ฉด, name=zerocho.sign์ด ๋๊ฒ ๋๊ณ req.signedCookies ๊ฐ์ฒด์ ๋ค์ด๊ฐ๊ฒ ๋จ
๐ ์ฟ ํค์ ์์ฑ๊ณผ ์ญ์
// ์ฟ ํค ์์ฑ
res.cookie('name', 'solarthenomad', {
expires: new Date(Date.now() + 900000),
httpOnly: true,
secure: true,
});
//์ฟ ํค ์ญ์
res.clearCookie('name', 'zerocho', { httpOnly: true, secure: true });
express-session ๋ฏธ๋ค์จ์ด
- express-session์ ์ธ์ ๊ด๋ฆฌ ์ ํด๋ผ์ด์ธํธ์ ์ฟ ํค๋ฅผ ๋ณด๋ธ๋ค.
express-session ๋ฏธ๋ค์จ์ด ํํ
app.use(session({
resave: false, // resave : ์์ฒญ์ด ์ฌ ๋ ์ธ์
์ ์์ ์ฌํญ์ด ์๊ธฐ์ง ์๋๋ผ๋ ์ธ์
์ ๋ค์ ์ ์ฅํ ์ง ์ค์ ํ๋ ๊ฒ
saveUninitialized: false, // saveUninitialized : ์ธ์
์ ์ ์ฅํ ๋ด์ญ์ด ์๋๋ผ๋ ์ฒ์๋ถํฐ ์ธ์
์ ์์ฑํ ์ง ์ค์ ํ๋ ๊ฒ
secret: process.env.COOKIE_SECRET, // cookie-parser์ secret๊ณผ ๊ฐ๊ฒ ์ค์ ํด์ฃผ๊ธฐ
cookie: {
httpOnly: true,
secure: false, // secure= false๋ก ํด์ https๊ฐ ์๋ ํ๊ฒฝ์์๋ ์ฌ์ฉํ ์ ์๊ฒ ํจ, ๋ฐฐํฌ์์๋ true๋ก ๋ฐ๊ฟ์ฃผ๊ธฐ
},
name: 'session-cookie', //name ์ค์ ์ ์ํด์ฃผ๋ฉด ๊ธฐ๋ณธ ์ธ์
์ด๋ฆ์ connect.sid์ด๋ค.
}));
- store๋ผ๋ ์ต์ ๋ ์๊ธดํ๋ฐ, ๋ฉ๋ชจ๋ฆฌ์ ์ธ์ ์ ์ ์ฅํ๋๋ก ํจ. ๊ทธ๋ฐ๋ฐ ํ ๋ฒ ์๋ฒ๋ฅผ ์ฌ์์ํ๋ฉด ๋ฉ๋ชจ๋ฆฌ๊ฐ ์ด๊ธฐํ๋๋ฉด์ ์ธ์ ์ด ๋ชจ๋ ๋ ์๊ฐ๋ค. โก ์ด๋ฅผ ๋ฐฉ์งํ๊ธฐ ์ํด store์ ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ฅผ ์ฐ๊ฒฐํด ์ธ์ ์ ์ ์งํ๋๋ฐ, redis๊ฐ ์ฌ์ฉ๋จ
์ธ์ ์์ฑ&์ ๊ฑฐ
req.session.name = 'solarthenomad'; // ์ธ์
๋ฑ๋ก
req.sessionID; // ์ธ์
์์ด๋ ํ์ธ
req.session.destroy(); // ์ธ์
๋ชจ๋ ์ ๊ฑฐ
next ๋์ ๊ตฌ์กฐ