728x90

익스프레스로 프로젝트 만들어보기

{
  "name": "study",
  "version": "0.0.1",
  "description": "study",
  "license": "ISC",
  "author": "",
  "type": "module",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "build": "tsc",
    "start": "ts-node src/app.ts"
  },
  "dependencies": {
    "express": "^5.2.1"
  },
  "devDependencies": {
    "@types/express": "^5.0.6",
    "@types/node": "^26.0.1",
    "nodemon": "^3.1.14",
    "ts-node": "^10.9.2",
    "typescript": "^6.0.3"
  }
}

위와 같이 package.json을 작성해주고, src/app.ts에 아래와 같이 작성하고 실행을 해보면 일단 된다.

 

import express from 'express';

const app = express();
app.set('port', process.env.PORT || 3000);

app.get('/', (req: express.Request, res: express.Response) =>
    res.send('Hello Seungkyu'),
);

app.listen(app.get('port'), () => console.log('Server on'));

 

그러고 3000번 포트로 적솝해보면 다음과 같이 나온다.

app.get으로 get요청만 처리했지만 다른 메서드들도 당연히 사용이 가능하다.

 

여기에 이전처럼 html을 읽어서 전송하고 싶다면

path를 사용해서 파일을 읽고, res.sendFile로 파일을 전송해버린다.

import express from 'express';
import { fileURLToPath } from 'url';
import { dirname } from 'path';

const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);

const app = express();
app.set('port', process.env.PORT || 3000);

app.get('/file', (req: express.Request, res: express.Response) =>
    res.sendFile(__dirname + '/test.html'),
);

app.get('/', (req: express.Request, res: express.Response) =>
    res.send('Hello Seungkyu'),
);

app.listen(app.get('port'), () => console.log('Server on'));

 

 

미들웨어

미들웨어는 요청과 응답 그 중간에 들어가서, express의 사실상 핵심의 역할을 한다고 한다.

저 app을 가져가서 app.use로 사용한다고 한다.

import express from 'express';

const app = express();
app.set('port', process.env.PORT || 3000);

app.use((req: express.Request, res: express.Response, next: express.NextFunction) => {
  console.log('미들 웨어 지나갑니다~');
  next();
});

app.get(
  '/',
  (req: express.Request, res: express.Response, next: express.NextFunction) => {
  console.log('get 요청 지나갑니다~');
});

app.listen(app.get('port'), () => {
  console.log(app.get('port'), '번 포트에서 대기 중');
})

이렇게 next도 파라미터로 받고, 미들웨어에서 무언가의 작업을 처리 한 후 next()를 호출해서 다음 어딘가로 흘려준다.

만약 next()를 호출하지 않으면, 그냥 거기서 멈춰버린다.

 

미들웨어는 3가지 경우에 실행이 되는데

app.use(미들웨어) -> 모든 요청에서 실행

app.use('/한승규', 미들웨어) ->  /한승규로 들어오는 요청에서 미들웨어를 실행

app.get('/한승규', 미들웨어) -> /한승규로 들어오는 get 요청에서 미들웨어를 실행

 

자 그럼 많이 사용하는 미들웨어 라이브러리들을 살펴보자.

우선 다음친구들을 설치한다.

{
  "name": "study",
  "version": "0.0.1",
  "description": "study",
  "license": "ISC",
  "author": "",
  "type": "module",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "build": "tsc",
    "start": "tsx src/app.ts"
  },
  "dependencies": {
    "cookie-parser": "^1.4.7",
    "dotenv": "^17.4.2",
    "express": "^5.2.1",
    "express-session": "^1.19.0",
    "morgan": "^1.11.0"
  },
  "devDependencies": {
    "@types/cookie-parser": "^1.4.10",
    "@types/express": "^5.0.6",
    "@types/express-session": "^1.19.0",
    "@types/morgan": "^1.9.10",
    "@types/node": "^26.0.1",
    "nodemon": "^3.1.14",
    "ts-node": "^10.9.2",
    "tsx": "^4.22.4",
    "typescript": "^6.0.3"
  }
}

 

다음과 같이 코드를 작성해보고, 여기에 들어있는 라이브러리들을 하나씩 확인해보자.

import express from 'express';
import morgan from 'morgan';
import cookieParser from 'cookie-parser';
import session from 'express-session';
import dotenv from 'dotenv';
import { fileURLToPath } from 'url';
import { dirname } from 'path';
import path from 'node:path';

const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);

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 || 'secret'));
app.use(
    session({
        resave: false,
        saveUninitialized: false,
        secret: process.env.SESSION_SECRET || 'secret',
        cookie: {
            httpOnly: true,
            secure: false,
        },
        name: 'session',
    }),
);

console.log(
    (
        req: express.Request,
        _res: express.Response,
        _next: express.NextFunction,
    ) => console.log(req.sessionID),
);

app.listen(app.get('port'), () => console.log('Server on'));

morgan

서버로 들어오는 클라이언트들의 로그를 남긴다.

어떤 ip로 들어왔는지까지는 안남기고 fastapi초럼 시간, 어디로 들어왔는지 이 정도만 남긴다.

morgan()안에 파라미터로 어떤 환경인지 넣으면 된다.

 

static

static 미들웨어는 spring의 resources와 같은 역할을 한다.

실제 서버에 있는 정적 파일들(html, css)등의 파일들을 해당 경로로 제공한다.

 

cookie-parser

cookie-parser는 요청에 들어있는 쿠키들을 조회해서 req.cookies 객체로 만들어준다고 한다.

아래와 같이 사용한다고 한다.

// 미들웨어 등록 시 비밀키를 넣어줍니다.
app.use(cookieParser('my_secret_key_1234'));

// 암호화된 쿠키 설정
app.get('/set-signed-cookie', (req, res) => {
    res.cookie('user_id', '12345', {
        maxAge: 60 * 60 * 1000, // 1시간
        httpOnly: true,
        signed: true // <-- 암호화 옵션 활성화
    });
    res.send('암호화된 쿠키 설정 완료!');
});

// 암호화된 쿠키 읽기
app.get('/get-signed-cookie', (req, res) => {
    // 암호화된 쿠키는 req.cookies 대신 req.signedCookies로 읽습니다.
    const userId = req.signedCookies.user_id;

    if (userId) {
        res.send(`인증된 유저 ID: ${userId}`);
    } else {
        res.send('쿠키가 없거나 위변조되었습니다.');
    }
});

 

미들웨어의 특성

미들웨어를 사용해보니, 일단 (req, res, next) 이렇게 오는 것을 볼 수 있었다.

next를 사용하면 다른 미들웨어로 보내주는거고, next를 사용하지 않는다면 send와 같은 마무리 함수를 호출해줘야 했다.

 

next에 인수를 넣을 수도 있다.

만약 인수를 넣는다면, 그 문자열의 다음 라우터 미들웨어로 이동한다.

또한 req.{이름} 등으로 req안에 데이터를 넣어둘 수도 있다.

 

multer

기존에는 json과 같은 데이터만 받았지만, 이번에는 multipartFile을 받아보도록 하자.

nest에서도 많이 봤던 친구라 익숙하다.

import express from 'express';
import morgan from 'morgan';
import cookieParser from 'cookie-parser';
import session from 'express-session';
import dotenv from 'dotenv';
import { fileURLToPath } from 'url';
import { dirname } from 'path';
import path from 'node:path';
import multer from 'multer';
import fs from 'node:fs';

const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);

dotenv.config();

const uploadDir = path.join(__dirname, 'public/uploads');
if (!fs.existsSync(uploadDir)) {
    fs.mkdirSync(uploadDir, { recursive: true });
}
const upload = multer({
    storage: multer.diskStorage({
        destination(req, file, cb) {
            cb(null, uploadDir);
        },
        filename(req, file, cb) {
            const ext = path.extname(file.originalname);
            cb(null, `${Date.now()}${ext}`);
        },
    }),
    limits: {
        fileSize: 5 * 1024 * 1024,
    },
});
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 || 'secret'));
app.use(
    session({
        resave: false,
        saveUninitialized: false,
        secret: process.env.SESSION_SECRET || 'secret',
        cookie: {
            httpOnly: true,
            secure: false,
        },
        name: 'session',
    }),
);

app.use((req, res, next) => {
    console.log('미들웨어 지나갑니다.');
    next();
});

app.post("/file", upload.single("file"), (req, res) => {
    console.log(req.file);
    res.send(req.file);
})

app.listen(app.get('port'), () => console.log('Server on'));

이렇게 postman으로 파일을 업로드해보니 잘 되는 것을 볼 수 있다.

 

파일을 제외한 나머지 정보는 req.body에서 가져오면 된다.

 

Router로 라우팅 주소 지정하기

그냥 이거도 fastapi에서의 라우터이다.

당연히 도메인바다 라우팅을 분리해야 하니, 라우터를 사용해 주소를 분리해보자.

우선 아래와 같이 router를 만들고

import express from 'express';

export const router = express.Router();

router.get('/', (req, res) => res.send('user'));
import express from 'express';
import dotenv from 'dotenv';
import { router as userRouter } from './routers/user.js';

dotenv.config();

const app = express();
app.set('port', process.env.PORT || 3000);

app.use('/user', userRouter);

app.listen(app.get('port'), () => console.log('Server on'));

이건 이제 가장 상위의 app.js이다.

 

이렇게 app.use로 라우터를 넣어주고, 그 경로를 지정하면 거기로 들어가는 요청이 다시 앞에 띠고 저 라우터로 들어간다.

이렇게 나오게 된다.

여기서 query, path param을 사용해보자.

다음과 같이 user.ts를 수정하고

import express from 'express';

export const router = express.Router();

router.get('/:id', (req, res) => {
    console.table(req.params);
    console.table(req.query);
    res.send('Hello Seungkyu');
});

 

여기에 path부터 테스트를 해보면

이렇게 나오고

 

다시 path variable을 빼고

import express from 'express';

export const router = express.Router();

router.get('/', (req, res) => {
    console.table(req.params);
    console.table(req.query);
    res.send('Hello Seungkyu');
});

다시 아래와 같이 요청해보면 잘 나오는 것을 볼 ㅜㅅ 있다.

 

express 세상의 req, res

계속 사용하는 req, res는 저번에 보았던 http를 다듬은 것이다.

많이 사용하는 것들만 대충 일단 표로 알아보고 가자.

req.app 맨날 사용하는 app 객체 자체를 접근 가능하다.
req.body body-parser가 만드는 request의 본문이 담겨있다.
req.cookies cookie-parser가 만드는 cookie의 객체가 담겨있다.
req.ip 클라이언트의 ip 주소가 담겨있다.
req.params path variable의 정보가 담겨있다.
req.query 쿼리 파라미터의 정보가 담겨있다.
req.signedCookies 서명된 쿠키들이 담겨있다.
req.get('헤더') 특정 헤더를 가져온다.

 

res.app 이거도 app 객체 자체에 접근한다.
res.cookie(key, value, option) 응답에 쿠키를 넣어서 보낸다.
res.clearCookie(key, value, option) 해당 쿠키를 제거한다.
res.end() 데이터없이 그냥 응답만 보낸다.
res.json(value) json 형식으로 응답을 보낸다.
res.redirect(주소) 해당 주소로 리다이렉트 응답을 보낸다.
res.send(value) 데이터를 넣어서 응답을 보낸다.
res.set(header, value) 응답의 헤더를 설정한다.
res.staus(httpStatus) http 코드를 지정한다.
res.sendFile(경로) 해당 경로의 파일로 응답한다.

'Node > Node.js' 카테고리의 다른 글

express로 mongodb 사용하기  (0) 2026.06.27
express로 pg 사용하기  (0) 2026.06.27
노드 패키지 매니저  (0) 2026.06.24
노드로 http 서버 만들어보기  (0) 2026.06.23
노드 사용해보기  (0) 2026.06.22

+ Recent posts