기존 http 모듈로 웹 서버를 만들어보니 코드를 읽기 힘들고, 확장성도 떨어졌다.
이를 프레임워크로 해결할 수 있다.
대표적인것이 express, Koa, Hapi가 있다.
app.set('port', 포트) >> 서버가 실행될 포드를 지정할 수 있다.
app.get('주소', 라우터) >> get요청이 올 때 어떤 동작을 할지 지정할수 있다.
app.listen('포트', 콜백) >> 몇번 포트에서 서버를 실행할지 지정할수 있다.
요청 한번에는 응답 한번이어야 하기 때문 하나의 라우터에서는 하나의 send만 보내야 한다. (미들웨어 포함)
(Error: Cannot set headers after they are sent to the client)
const express = require("express");
const app = express();
app.set("port", 3001);
app.get("/", (req, res) => {
res.send("hello express");
});
app.get("/list", (req, res) => {
res.status(200).send("show list");
});
// 200이 생략되어있다.
app.listen(app.get("port"), () => {
console.log("익스프레스 실행");
});
path를 사용해서 경로처리를 해준다.
const path = require("path");
app.get("/", (req, res) => {
res.sendFile(path.join(__dirname, "index.html"));
});
use의 3번쨰 파라미터에는 next가 존재하는데 이 next를 실행시켜줘야 라우터에 맞게 실행된다.
next 다음미들웨어가 있다면 해당 미들웨어가 실행된 후 라우터로 이동한다.
next('router')가 있다면 뒤의 코드들을 무시하고 다음 라우터를 찾아 떠난다.
app.use((req, res, next) => {
console.log('모든 요청에 실행된다.')
next();
})
app.use('/about', (req, res, next) => {
console.log('about에서만 실행된다.')
next();
})
파라미터가 4개가 다 있어야한다. next까지.
첫번째 err에는 에러에 관한 정보가 담긴다.
res.status 메서드로 http 상태 코드를 지정이 가능하다.
에러 처리 믿르웨어를 안 연결해도 익스프레스가 알아서 처리되긴 한다.
특별한 경우가 아니라면 가장 하단에 위치해야 한다.
app.use((err, req, res, next) => {
console.error(err)
res.send('에러가 발생했습니다.')
})
위쪽 미들웨어에 next에 error를 넣어주면 에러처리를 한 미들웨어가 실행된다.
app.use((req, res, next) => {
console.log('상단의 미들웨어입니다.');
next()
}, (req, res, next) => {
try {
console.log('실행')
} catch (error) {
next(error)
}
})
요청들을 보여준다.
dev말고 combined를 사용하면 좀 더 자세한 정보를 알려준다.
const morgan = require("morgan");
app.use(morgan("dev"));
요청 헤더의 쿠키를 해석해주는 미들웨어
app.use(cookieParser(비밀키))의 비밀키로 내 서버가 만든 쿠키임을 검증할 수 있다.
const cookieParser = require("cookie-parser");
app.use(cookieParser('mypassword'));
app.get("/", (req, res) => {
req.cookies;
res.cookie("name", encodeURIComponent(name), {
expires: new Date(),
httpOnly: true,
path: "/",
});
// 'Set-Cookie': `name=${encodeURIComponent(name)}; Expires=${expires.toGMTString()}; HttpOnly; Path=/`
// 길었던것을 더 간단하고 보기좋게 코딩 가능
res.sendFile(path.join(__dirname, "index.html"));
});
clearCookie로 쿠키를 삭제할 수도 있다.
res.clearCookie('name', encodeURIComponent(name), {
httpOnly: true,
path: '/',
})
세션 관리용 미들웨어
세션 쿠키에 대한 설정(secret: 쿠키 암호화, cookie: 세션 쿠키 옵션)
세션 쿠키는 앞에 s%3A가 붙은 후 암호화되어 프런트에 저장된다.
resave: 요청이 왔을 때 세션에 수정사항이 생기지 않아도 다시 저장할지 여부
saveUninitialized: 세션에 저장할 내역이 없더라도 세션을 저장할지
req.session.save로 수동 저장도 가능하긴 하다.
const session = require("express-session");
app.use(
session({
resave: false,
saveUninitialized: false,
secret: "mypassword",
cookie: {
httpOnly: true,
},
name: "connect.sid",
})
);
미들웨어 안에 미들웨어 넣기
뒤에 (req,res,next) 를 붙여주면, 로직을 확장할 수 있다.
app.use((req,res,next) => {
if (process.env.Node_ENV === 'production') {
morgan('combined')(req,res,next);
} else {
morgan('dev')(req,res,next)
}
})
user.js 에서 '/'인 이유는 이미 app.use("/user", userRouter);으로 /user에 진입한 후의 경로이기 때문
// index.js
const express = require("express");
const router = express.Router();
router.get("/", (req, res) => {
res.send("hello express");
});
module.exports = router;
/:name으로 받아서 req.params.name으로 알수 있다.
query ( ?limit=4&skip=12 )의 경우는 req.query로 받을수 있다.
// user.js
const express = require("express");
const router = express.Router();
router.get("/:name", (req, res) => {
res.send(`hello user! ${req.params.name}`);
});
module.exports = router;
// app.js
const indexRouter = require("./routes/index");
const userRouter = require("./routes/user");
//...
app.use("/", indexRouter);
app.use("/user", userRouter);
//...