설치
npm i express
npm i -D nodemon
항상 package.json을 제일 먼저 생성해야합니다. package.json을 생성해주는 npm init 명령어를 콘솔에서 호출해 단계적으로 내용물을 입력해도 되고 npm init -y를 입력해 파일을 만든뒤 내용을 수정해도 됩니다. version, description, author, license는 원하는대로 자유롭게 수정해도 괜찬습니다.
package.json
{
"name": "nodeexpress",
"version": "1.x.x",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "nodemon app" // 입력확인 node start으로 호출 가능
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"express": "^x.xx.x"
},
"devDependencies": {
"nodemon": "^x.x.x"
}
}
scripts 부분에 start 속성을 잊지 말고 넣어줘야 합니다. nodemon app을 하면 app.js를 nodemon으로 실행한다는 뜻입니다. 서버 콛에 수정 사항이 생길 때마다 매번 서버를 재시작 하기는 귀찮으므로 nodemon 서버를 자동으로 재시작하며, nodemon이 실행되는 콘솔에 rs를 입력해서 수동으로 재시작할 수도 있습니다.
nodemon은 개발용으로만 사용할 것을 권장합니다. 배포 후에는 서버 코드가 빈번하게 변경될 일이 없으므로 nodemon을 사용하지 않아도 됩니다.
클라이언트는 특정한 HTTP 요청 메소드(GET, POST 등)나 서버의 특정 URI(또는 경로)로 HTTP 요청을 보낸다. 라우팅은 클라이언트의 요청에 해당하는 메소드와 Endpoint에 따라 서버가 응답하는 방법을 결정하는 것이다.
// index.js
const express = require('express');
const app = express()
const port = 8080
app.get('/', (req, res)=> {
res.send(`<html>
<head>
<tilte>서버 테스트</<title>
</head>
<body>하이</body>
</html>`);
// console.log("의미가 있을까?"); 없다
})
app.listen(port, ()=> {
console.log("8080 port server open");
})
Express 모듈을 실행해app 변수에 할당합니다. 익스프레스 내부에 http 모듈이 내정되어 있으므로 서버의 역할을 할 수 있습니다.
app.set('port', 포트)로 서버가 실행될 포트를 설정합니다. process.env 객체에 PORT속성이 있다면 그 값을 사용하고, 없다면 기본값으로 3000번 포트를 이용하도록 되어 있습니다. 이렇게 app.set(키, 값)을 사용해서 데이터를 저장할 수 있으며, 나중에 데이터를 app.get(키) 로 가져올 수 있습니다.
app.get(주소, 라우터)는 주소에 대한 GET 요청이 올 때 어떤 동작을 할지 적는 부분입니다. 매개변수 req는 요청에 관한 정보가 들어 있는 객체이고 , res는 응답에 관한 정보가 들어 있는 객체입니다. 현재 GET/ 요청 시 응답으로 Hello, Express를 전송합니다. 익스프레스에서는 res.write나 res.end 대신 res.send를 사용하면됩니다.
GET 요청 외에도 POST, PUT, PATCH, DELET , OPTIONS 에 대한 라우터를 위한 app.post, app.put, app.patch, app.delete, app.options 메서드가 존재합니다.
listen을 하는 부분은 http 웹 서버와 동일합니다. 서버를 구동했던 것과 동일하게 포트를 연결하고 서버를 실행합니다.

단순 문자열 대신 HTML로 응답하고 싶다묜 res.sendFile 메서드를 사용하면 됩니다. 단, 파일의 경로를 path 모듈을 사용해서 지정해야합니다.
// index.html
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>익스프레스 서버</title>
</head>
<body>
<h1>익스프레스</h1>
<h2>배워봅시다</h2>
<div id="container">
<table style="border: 1px solid black">
<thead>
<tr>
<td>1</td>
<td>2</td>
<td>3</td>
<td>4</td>
<td>5</td>
</tr>
</thead>
<tbody></tbody>
</table>
</div>
</body>
</html>
app.js
const express = require("express");
const path = require("path");
const app = express();
app.set("port", process.env.PORT || 8000);
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)에 위치하기 때문에 미들웨어(middleware)라고 부르는 것입니다. 뒤에 나오는 라우터와 에러 핸들러 또한 미들웨어의 일종이므로 미들웨어가 익스프레스의 전부라고 해도 과언이 아닙니다. 미들웨어는 요청과 응답을 조작해 기능을 추가하기도 하고, 나쁜 요청을 걸러내기도 합니다.
미들웨어는 app.use와 함께 사용됩니다. app.use(미들웨어) 꼴입니다. 익스프레스 서버에 미들웨어를 연결해봅시다.
// app.js
...
app.set("port", process.env.PORT || 8000);
app.use((req, res, next) => {
console.log("모든 요청이 실행됩니다");
next();
});
app.get(
"/",
(req, res, next) => {
console.log("GET/ 여청에서만 실행됩니다.");
next();
},
(res, req) => {
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"), "번 포트에서 대기중");
});
app.use에 매개변수가 req,res,next인 함수를 넣으면 됩니다. 미들웨어는 위에서부터 아래로 순서대로 실행되면서 요청과 응답 사이에 특별한 기능을 추가할 숭 있습니다. 이번에는 next라는 세번째 매개변수를 사용했는데, 다음 미들웨어로 넘어가는 함수입니다. next를 실행하지 않으면 다음 미들웨어가 실행되지 않습니다.
주소를 첫 번째 인수로 넣어주지 않는다면 미들웨어는 모든 요청에서 실행되고, 주소를 넣는다면 해당하는 요청에서만 실행된다고 보면 됩니다.
app.use(미들웨어) | 모든 요청에서 미들웨어 실행 |
app.use('/abc', 미들웨어) | abc로 시작하는 요청에서 미들웨어 실행 |
app.post('/abc', 미들웨어) | abc로 시작하는 POST 요청에서 미들웨어 실행 |
app.use나 app.get 같은 라우터에 미들웨어를 여러 개 장착할 수 있습니다. 현재 app.get 라우터에 미들웨어가 두 개 연결되어 있습니다. 다만, 이때도 next를 호출해야 다음 미들웨어러 넘어갈 수 있습니다.
현재 app.get('/')의 두 번째 미들웨어에서 에러가 발생하고, 이 에러는 그 아래에 있는 에러 처리 미들웨어에 전달됩니다.
에러 처리 미들웨어는 매개변수가 err, req, res, next로 네 개입니다. 모든 매개변수를 사용하지 않더라도 매개변수가 반드시 네 개여야 합니다. 첫 번째 매개변수 err에는 에러에 관한 정보가 담겨 있습니다. res.status 메서드로 HTTP 상태 코드를 지정할 수 있으며 , 기본값은 200(성공)입니다. 에러 처리 미들웨어를 직접 연결하지 않아도 기본적으로 익스프레스가 에러를 처리하긴 합니다. 하지만 실무에서는 직접 에러 처리 미들웨어를 연결해주는 것이 좋습니다. 에러 처리 미들웨어는 특별한 경우가 아니면 가장 아래에 위치하도록 합니다.

1. static
static 미들웨어는 정적인 파일들을 제공하는 라우터 역할을 합니다. 기본적으로 제공되기에 따로 설치할 필요 없이 express 객체 안에서 꺼내 장착하면 됩니다.
app.use('요청 경로', express.static('실제 경로'));
app.use('/', express.static(path.join(__dirname, 'public')));
함수의 인수로 정적 파일들이 담겨 있는 폴더를 지정하면 됩니다. 현재 public 폴더가 지정되어 있습니다. 예를 들어 public/stylesheets/style.css는 http://localhost:8000/stylesheets/style/css 로 접근할 수 있습니다. public 폴더를 만들고 나서 css, js 나 이미지 파일들을 public 폴더에 넣으면 브라우저에서 접슨할 수 있게 됩니다.
실제 서버의 폴더 경로에는 public이 들어 있지만, 요청 경로가 다르므로 외부인이 서버의 구조를 쉽게 파악할 수 없습니다. 이는 보안에 큰 도움이 됩니다.
또한 정적 파일들을 알아소 제공해주므로 fs.readFile로 파일을 직접 읽어서 전송할 필요가 없습니다. 만약 요청에 경로에 해당하는 파일이 없으면 알아서 내부적으로 next를 호출합니다. 파일을 발견했다면 다음 미들웨어는 실행되지 않습니다. 응답으로 파일을 보내고 next를 호출 하지 않으니까요.
2. body-parser
요청의 본문에 있는 데이터를 해석해서 req.body 객체로 만들어주는 미들웨어입니다. 보통 폼데이터나 AJAX 요청의 데이터를 처리합니다. 단, 멀티파트(이미지, 동영상, 파일) 데이터는 처리하지 못합니다(multer 모듈을 사용합니다).
body-parser 미들웨어는 다음과 같이 사용합니다.
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
다른 책이나 코드에서 body-parser를 설치하는 것을 볼 수도 있습니다. 하지만 익스프레스 4.16.0버전부터 body-parser 미들웨어의 일부 기능이 익스프레스에 내장되었ㅇ므로 따로 설치 할 필요가 없습니다.
단, body-parser를 직접 설치해야 하는 경우도 있습니다. body-parser는 JSON과 URL-encoded 형식의 데이터 외에도 Raw, Text 형식의 데이터를 추가로 해석할 수 있습니다.
Raw는 요총의 본문이 버퍼 데이터일 때, Text는 텍스트 데이터일 때 해석하는 미들웨어입니다. 버퍼나 텍스트 요청을 처리할 필요가 있다면 body-parser를 설치한 후 다음과 같이 투가합니다.
$ npm i body-parser
요청 데이터 종류에 대해 간단히 살펴봅시다.JSON은 JSON 형식의 데이터 전달 방식이고, URL-encoded는 주소 형식으로 데이터를 보내는 방식입니다, 폼 전송은 URL-encode 방식을 주로 사용합니다. urlencoded 메서드를 보면 { extended: false } 라는 옵션이 들어 있습니다.이 옵션이 false이면 노드의 querystring 모듈을 사용해 쿼리스트링을 해석하고, true이면 qs 모듈을 사용해 쿼리스트링을 해석합니다. qs 모듈은 내장 모듈이 아니라 nqm 패키지이며, querystring 모듈의 기능을 좀 더 확장한 모듈입니다.
POST, PUT 요청의 전달받으려면 req.on('data') 와 req.on('end')로 스트림을 사용해야 했을 것이다. body-parser를 사용하면 그럴 필요 없이 이 패키지가 내부적으로 스트림을 처리해 req.body에 추가합니다.
예를 들어, JSON 형식으로
{
'name': 'zerocho',
'book': 'nodejs'
}
본문으로 보낸다면 req.body에 그대로 들어갑니다. URL-encoded 형식으로 name=zerocho&book=nodejs를 본문으로 보낸다면 req.body에 { 'name': 'zerocho', 'book': 'nodejs'} 가 들어갑니다.
3. cookie-parser
cookie-parser는 요청에 동봉된 쿠키를 해석해 req,cookies 객체로 만듭니다.
app.use(cookieParser(비밀 키));
해석된 쿠키들은 req.cookies 객체에 들어갑니다. 예를 들어 name=sang 쿠키를 보냈다면 req.cookies는 {name: 'sang'} 가 됩니다. 유효 기간이 지난 쿠키는 알아서 걸러냅니다.
첫 번째 인수로 비밀 키를 넣어줄 수 있습니다. 서명된 쿠키가 있는 경우, 제공한 비밀 키를 통해 해당 쿠키가 내 서버가 만든 쿠키임을 검증할 수 있습니다. 쿠키는 클라이언트에서 위조하기 쉬우므로 비밀 키를 통해 만들어낸 서명을 쿠키 값 뒤에 붙입니다. 서명이 붙으묜 쿠키가 name=sang.sign과 같은 모양이 됩니다. 서명된 쿠키는 req.cookies 대신 req.signedCookies 객체에 들어 있습니다.
cookie-parser가 쿠키를 생성할 때 쓰이는 것은 아닙니다. 쿠키를 생성/ 제거하려면 res.cookie, res.clearCookie 메서드를 사용해야 합니다. res.cookie(키, 값, 옵션) 형식으로 사용합니다. 옵션은 domain, httpOnly, maxAge, path, secure 등이 있습니다.
res.cookie('name', 'sang', {
expires: new Date(Date.now() + 90000),
httpOnly: true,
secure: true,
});
res.clearCookie('name', 'sang', { httpOnly: true, secure: true});
쿠키를 지우려면, 키와 값외에 옵션도 정확히 일치해야 쿠키가 지워집니다. 단, expires 나 maxAge 옵션은 일치할 필요가 없습니다.
옵션 중에는 signed 라는 옵션이 있는데, 이를 true로 설정하면 쿠키 뒤에 서명이 붙습니다. 내 서버가 쿠키를 만들었다는 것을 검증할 수 있으므로 대부분의 경우 서명 옵션을 켜두는 것이 좋습니다. 서명을 위한 비밀 키는 cookieParser 미들웨어에 인수로 넣은 process.env.COOKIE_SECRET이 됩니다.
미들웨어의 특성 활용하기
app.use((req, res, next) => {
console.log("모든 요청에 다 실행합니다")
next()
});
미들웨어는 req , res, next 를 매개변수로 갖는 함수 (에러 처리 미들웨어만 예외적으로 err, req, res, next를 가집니다)로서 app.use 나 app.get, app.post 등으로 장착하빈다. 특정한 주소의 요청에만 미들웨어가 실행되게 하려면 첫 번째 인수로 주소를 넣으면 됩니다.
app.use(
morgan('dev'),
express.static('/', path.join(__dirname, 'public')),
express.json(),
express.urlencoded({extended: false}),
CookieParser(process.env.COOKIE_SECRET)
);
위와 같이 동시에 여러 개의 미들웨어를 장착할 수도 있으며, 다음 미들웨로 넘어가려면 NEXT 함수를 호출해야합니다. 위 미들웨어들은 내부적으로 next를 호출하고 있으므로 연달아 쓸 수 있습니다. next를 호출하지 않는 미들웨어는 res.send나 res.sendFile 등의 메서드로 응답을 보내야 합니다. express.static과 같은 미들웨어는 정적파일을 제공할 때 next 대신 res.sendFile 메서드로 응답을 보냅니다. 따라서 정적 파일을 제공하는 경우 express.json, express.urlencoded, cookieParser 미들웨어는 실행되지 않습니다. 미들웨어 장착 순서에 따라 어떤 미들웨어는 실행되지 않을 수도 있다는 것을 기억해둡시다.
만약 next도 호출하지 않고 응답도 보내지 않으면 클라이언트는 응답을 받지 못해 하염없이 기다리게 됩니다.

지금까지는 next에 아무런 인수를 넣지 않았지만 next 함수에 인수를 넣을 수도 있습니다. 단, 인수를 넣는다면 특수한 동작을 합니다. route라는 문자열을 넣으면 다음 라우터의 미들웨어로 바로 이동하고, 그 외의 인수를 넣는다면 바로 에러 처리 미들웨어로 이동합니다. 이때의 인수는 에러 처리 미들웨어의 err 매개변수가 됩니다. 라우터에서 에러가 발생할 때 에러를 next(err)를 통해 에러 처리 미들웨어로 넘깁니다.
'nodeJS' 카테고리의 다른 글
[Node.js] Router 객체로 라우팅 분리 (0) | 2023.09.13 |
---|---|
[Node.js] 예외 처리하기 (0) | 2023.09.07 |
[Node.js] Net 모듈 (0) | 2023.08.31 |
[Node.js] 통신(네트워크) (0) | 2023.08.30 |
[Node.js] 내장 모듈 , require (0) | 2023.08.29 |