해당 글은 Node.js 교과서의 내용을 요약, 정리한 글입니다.
//package.json
{
"name":"learn-express",
"version":"0.0.1",
"description":"익스프레스를 배우자",
"main":"app.js",
"scripts":{
"start":"nodemon app"
},
"author":"ZeroCho",
"license":"MIT"
}
$npm i express
$npm i -D nodemon
scripts부분에 start속성은 잊지 말고 넣어야 한다. nodemon app을 하면 app.js를 nodemon으로 실행해야 한다는 것이다.
nodemon이 실행되는 콘솔에 rs를 입력해서 수동으로 재시작할 수도 있다.
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'),'번 포트에서 대기 중');
});
단순한 문자열 대신 HTML로 응답하고 싶다면 res.sendFile메서드를 사용하면 된다. 단, 파일의 경로를 path모듈을 사용해서 지정해야 한다.
//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.sendFile(path.join(__dirname, '/index.html'));
});
app.listen(app.get('port'),()=>{
console.log(app.get('port'),'번 포트에서 대기 중');
});
익스프레스의 핵심, 요청과 응답의 중간에 위치하여 미들웨어라고 부른다.
미들웨어는 app.use와 함께 사용된다. app.use(미들웨어)꼴이다.
//app.js
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 Erroro('에러는 에러 처리 미들웨어로 간다');
});
app.use((err, req,res,next)=>{
console.error(err);
res.status(500).send(err.message);
});
app.listen(app,get('port'),()=>{
...
미들웨어는 위에서부터 아래로 순서대로 실행되면서 요청과 응답 사이에 특별한 기능을 추가할 수 있다.
next는 다음 미들웨어로 넘어가는 함수이다.
$npm i morgan cookie-parser express-session dotenv
dotenv는 process.env를 관리하기 위한 패키지이며, 다른 패키지는 미들웨어다.
//app.js
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();
const app = express();
app.set('port',process.env.PORT||3000);
app.use(morgan('dev'));
app.use('/',express.static(path.join(__dirname,'public')));
app.use(express.json());
app.use(express.urlencoded({ extended: false}));
app.use(cookieParser(process.env.COOKIE_SECRET));
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();
});
...
//.env
COOKIE_SECRET = cookiesecret
dotenv패키지는 .env파일을 읽어서 process.env
로 만든다.
process.env.COOKIE_SECRET
에 cookiesecret
값이 할당된다.
morgan에 연결 후 접속하면 기존 로그 외에 추가적인 로그를 볼 수 있다.
app.use(morgan('dev'));
로 사용한다.
static 미들웨어는 정적인 파일들을 제공하는 라우터 역할을 한다. 기본적으로 제공되기에 따로 설치할 필요 없이 express객체 안에서 꺼내 장착하면 된다.
app.use('요청 경로', express.static('실제 경로')); app.use('/', express.static(path.join(\_\_dirname, 'public')));
public폴더를 만들고 css나 js, 이미지 파일들을 public 폴더에 넣으면 브라우저에서 접근할 수 있다.
정적 파일을 알아서 제공해주므로 fs.readFile로 파일을 직접 읽어서 전송할 필요가 없다.
본문에 있는 데이터를 해석해서 req.body
객체로 만들어주는 미들웨어다.
단, 멀티파트 데이터는 처리하지 못한다. 멀티파트 데이터는 multer
모듈을 사용하면 된다.
익스프레스 4.16.0버전부터 body-parser
미들웨어의 일부 기능이 익스프레스에 내장되었으므로 따로 설치할 필요가 없다.
하지만, 버퍼나 텍스트 요청을 처리할 필요가 있다면body-parser
를 설치한 후
//콘솔
$npm i body-parser
//코드
const bodyParser = require('body-parser');
app.use(bodyParser.raw());
app.use(bodyParser.text());
를 추가합니다.
요청에 동봉된 쿠키를 해석해 req.cookies
객체로 만든다.
app.use(cookieParser(비밀키));
이러한 방식으로 사용한다.
첫 번째 인수로 비밀 키를 넣어줄 수 있다. 제공한 비밀 키를 통해 해당 쿠키가 내 서버가 만든 쿠키임을 검증할 수 있다.
쿠키는 클라이언트에서 위조하기 쉬우므로 비밀 키를 통해 만들어낸 서명을 쿠키 값 뒤에 붙인다.
서명이 붙으면 쿠키가 name=zerocho.sign
과 같은 모양이 된다.
서명된 쿠키는 req.cookies
대신 req.signedCookies
객체에 들어 있다.
쿠키를 생성/제거하기 위해서는 res cookie, res.clearCookie
매서드를 사용해야 한다.
쿠키를 지우려면 키와 값 외에 옵션도 정확히 일치해야 쿠키가 지워진다.
expires나 maxAge옵션은 일치할 필요가 없다.
세션 관리용 미들웨어다.
인수로 세션에 대한 설정을 받는다.
resave
는 요청이 올 때 세션에 수정 사항이 생기지 않더라도 세션을 다시 저장할지 설정하는 것이다.
saveUnitialized
는 세션에 저장할 내용이 없더라도 처음부터 세션을 생성할지 설정한다.
express-session은 세션 관리 시 클라이언트에 쿠키를 보낸다.
store
라는 옵션도 있다. 설정하지 않으면 메모리에 세션을 저장하기 때문에 배포 시에는 store에 데이터베이스를 연결하여 세션을 유지하는 것이 좋다.
미들웨어는 req, res, next(에러 처리 미들웨어 제외)를 매개변수로 가지는 함수이다.
app.use(
morgan('dev'),
express.static('/',path.join(\_\_dirname, 'public')),
express.json(),
express.urlencoded({extended:false}),
cookieParser(process.env.COOKIE_SECRET),
);
위와 같이 동시에 여러 개의 미들웨어를 장착할 수도 있으며, 다음 미들웨어로 넘어가려면 next 함수를 호출해야 한다.
next를 호출하지 않는 미들웨어는 res.send나 res.sendFile등의 메서드로 응답을 보내야 한다.
express.static과 같은 미들웨어는 정적 파일을 제공할 때 next 대신 res.sendFile메서드로 응답을 보낸다.
따라서 정적 파일을 제공하는 경우 express.json, express.urlencoded, cookieParser미들웨어는 실행되지 않는다.
next
에 인수를 넣을 수도 있다. 'route'라는 문자열을 넣으면 다음 라우터의 미들웨어로 바로 이동하고, 그 외의 인수를 넣는다면 바로 에러 처리 미들웨어로 이동한다. 이때의 인수는 에러 처리 미들웨어의 err매개변수가 된다.
미들웨어 간에 데이터를 전달하는 방법도 있다.
req.session객체에 데이터를 넣어도 되지만, 세션이 유지되는 동안에 데이터도 계속 유지된다는 단점이 있다.
만약, 요청이 끝날때 까지만 데이터를 유지하고 싶다면 req객체에 데이터를 넣어두면 된다.
app.use((req, res, next)=>{
req.data = '데이터 넣기';
next();
},(req,res,next)=>{
console.log(req.data);
next();
});
이런 방식을 이용한다면 요청이 처리되는 동안 data를 통해 미들웨어 간에 데이터를 공유할 수 있다. 새로운 요청이 오면 req.data는 초기화된다.
미들웨어 안에 미들웨어를 넣는 방법도 있다.
app.use((req, res,next)=>{
if(process.env.NODE_ENV === 'production'){
morgan('combined')(req,res,next);
} else {
morgan('dev')(req,res,next);
}
});
이미지, 동영상 등을 비롯한 여러 가지 파일들을 멀티파트 형식으로 데이터를 업로드할 수 있다.
이러한 폼을 통해 업로드하는 파일은 body-parser로는 처리할 수 없고 직접 파싱하기도 어려우므로 multer라는 미들웨어를 따로 사용하면 편리하다.
multer는 함수의 인수로 설정을 넣는다.
storage속성에는 어디에 어떤 이름으로 저장할지를 넣는다.
limits 속성에는 업로드에 대한 제한 사항을 설정할 수 있다.
설정이 끝나면 변수가 생성된다.
파일을 하나만 업로드하는 경우 single 미들웨어를 사용한다.
app.post('/upload',upload.single('image'),(req,res)=>{
console.log(req.file,req.body);
res.send('ok');
});
여러 파일을 업로드 하는 경우에는 single대신 array로 교체한다.
app.post('/upload',
upload.fields([{name:'image1'},{name:'image2'}]),
(req,res)=>{
console.log(req.files, req.body);
res.send('ok');
},
);
익스프레스를 사용하는 이유 중 하나는 바로 라우팅을 깔끔하게 관리할 수 있다는 점이다.
//routes/index.js
const express = require('express');
const router = express.Router();
router.get('/', (req,res)=>{
res.send('Hello, Express');
});
module.exports = router;
//routes/user.js
const express = require('express');
const router = express.Router();
router.get('/',(req,res)=>{
res.send('Hello, User');
});
module.exports = router;
//app.js
...
const path = require('path');
dotenv.config();
const indexRouter = require('./routes');
const userRouter = require('./routes/user');
...
name: 'session-cookie',
}));
app.use('/',indexRouter);
app.use('/user',userRouter);
app.use((req,res,next)=>{
res.status(404).send('Not Fount');
});
app.use((err,req,res,next)=>{
...
router.get('/user/:id',function(req,res){
console.log(req.params, req.query);
});
:id는 해당하는 값을 입력받을 수 있다.
때문에
/user/:id
같은 라우터 위에 /user/like
같은 라우터가 위치해야 한다.
다음과 같은 코드를 하나의 덩어리로 줄일 수 있다.
router.get('/abc',(req,res)=>{
res.send('GET /abc');
});
router.post('/abc',(req,res)=>{
res.sned('POST /abc');
});
router.route('/abc')
.get((req,res)=>{
res.send('GET /abc');
})
.post((req,res)=>{
res.send('POST /abc');
});
//req 객체
req.app
//req 객체를 통해 app객체에 접근할 수 있다.
req.body
//body-parser 미들웨어가 만드는 요청의 본문을 해석한 객체이다.
req.cookies
//cookie-parser 미들웨어가 만드는 요청의 큐키를 해석한 객체
req.ip
//요청의 ip주소가 담겨 있다.
req.params
//라우트 매개변수에 대한 정보가 담긴 객체
req.query
//쿼리스트링에 대한 정보가 담긱 객체
req.signedCookies
//서명된 쿠키들은 여기에 담겨 있다.
req.get(헤더 이름)
//헤더의 값을 가져오고 싶을 때 사용한다.
//res 객체
res.app
//res객체를 통해 app 객체에 접근할 수 있다.
res.cookie(키, 값, 옵션)
//쿠키를 설정하는 메서드
res.clearCookie(키, 값, 옵션)
//쿠키를 제거하는 메서드
res.end()
//데이터 없이 응답을 보낸다.
res.json(JSON)
//JSON형식의 응답을 보낸다.
res.redirect(주소)
//리다이렉트할 주소와 함께 응답을 보낸다.
res.render(뷰, 데이터)
//템플릿 엔진을 렌더링해서 응답할 때 사용하는 메서드
res.send(데이터)
//데이터와 함께 응답을 보낸다.문자열일 수도 있고 HTML일 수도 있고, 버퍼나 객체, 배열일 수 있다.
res.sendFile(경로)
//경로에 위치한 파일을 응답한다.
res.set(헤더, 값)
//응답의 헤더를 설정한다.
res.status(코드)
//응답 시의 HTTP상태 코드를 지정한다.
템플릿 엔진은 자바스크립트를 사용해서 HTML을 렌더링 할 수 있게 한다.
...
app.set('port', process.env.PORT||3000);
app.set('views',path.join(__dirname,'views'));
app.set('view engine','pug');
app.use(morgan('dev'));
...
기존 HTML과는 다르게 < >, </>가 없습니다.
탭 또는 스페이스로만 태그의 부모자식관계를 규명한다.
<!DOCTYPE html>
<html>
<head>
<title>익스프레스</title>
<link rel="stylesheet" href="/style.css"/>
</head>
</html>
->
doctype html
html
head
title= title
link(rel='stylesheet',href='/stylesheets/style.css')
또한, 속성 중 아이디와 클래스가 있다면 다음과 같이 표한할 수 있다.
<div id="login-button"></div>
<div class="post-image"></div>
<span id="highlight"></span>
<p class="hidden full"></p>
->
#login-button
.post-image
span#highlight
p.hidden.full
에디터에서 텍스트를 여러 줄 입력하고 싶다면 파이프를 넣는다.
<p>
안녕하세요. 여러 줄을 입력합니다.
<br />
태그도 중간에 넣을 수 있습니다.
</p>
->
p
|안녕하세요.
|여러 줄을 입력합니다.
br
|태그도 중간에 넣을 수 있습니다.
style이나 script 태그는
style.
h1{
font-size:30px;
}
script.
const message = 'Pug';
alert(message);