[node-js] 개념 정리

오동훈·2021년 8월 24일
0

node-js

목록 보기
1/1

1. Express

1. express

HTTP 요청에 대하여 라우팅 및 미들웨어 기능을 제공하는 웹 프레임워크(서버 구축을 위한 프레임워크)

설치

npm install express --save

프로젝트 파일 및 폴더 구조

  • app.js 파일: 핵심적인 서버 역할. 주로 미들웨어 위치.
  • bin 폴더: 서버의 로직을 작성하는 곳
    • www 파일: 서버를 실행하는 스크립트
  • public 폴더: 외부(클라이언트)에서 접근 가능한 파일(이미지, 자바스크립트, CSS 파일)들을 모아둔 곳
  • routes 폴더: 주소별 라우터들을 모아둔 곳
  • views 폴더: 템플릿 파일(화면 부분)을 모아둔 곳

실행

const express = require('express')
const app = express()
const port = 3000

app.get('/', (req, res) => {
  res.send('Hello World!')
})

app.listen(port, () => {
  console.log(`Example app listening at http://localhost:${port}`)
})

//---------------------------------//

// 위와같이 작성하고 아래와 같이 실행하면 서버가 실행되게 된다.
>>> node app.js

하지만 이런 경우 코드를 수정할때마다 서버를 내렸다 올렸다를 반복해야 되는데, 번거로운 과정을 생략할 수 있는 좋은 패키지가 하나 있다! 바로 nodemon이다.

nodemon

// nodemon 설치 명령어
npm i -g nodemon

nodemon을 설치한 후 실행하면 소스코드가 바뀔때마다 자동으로 서버가 재시작되어 매우 편리하다.

2. express 구조

app.js 파일

핵심 서버 역할. 주로 미들웨어가 위치한다.

var app = express(); // express 패키지를 호출하여 app 변수 객체 생성

app.set() 메서드: 익스프레스 앱 설정

app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'pug');

app.use() 메서드: 미들웨어 연결

/* 주요 미들웨어 */
app.use(logger('dev')); // morgan: 요청 정보를 콘솔에 기록
app.use(express.json()); // 요청 들어온 본문을 JSON으로 해석
app.use(express.urlencoded({ extended: false })); // 요청 들어온 본문을 querystring을 사용하여 해석
app.use(cookieParser()); // cookie-parser: 요청에 동봉된 쿠키 해석
app.use(express.static(path.join(__dirname, 'public'))); // 정적 파일이 담긴 폴더 설정

/* 라우팅 미들웨어 */
app.use('/', indexRouter);
app.use('/users', usersRouter);

/* 404(Not Found) 처리 미들웨어 */
app.use(function(req, res, next) {
  next(createError(404));
});

/* 에러 처리 미들웨어 */
app.use(function(err, req, res, next) {
  // set locals, only providing error in development
  res.locals.message = err.message;
  res.locals.error = req.app.get('env') === 'development' ? err : {};

  // render the error page
  res.status(err.status || 500);
  res.render('error');
});

// bin/www 파일에서 사용하기 위한 app 객체 모듈화
module.exports = app;

bin/www 파일

http 모듈에 express 모듈 연결 및 접속 포트 지정

var app = require('../app');
var debug = require('debug')('learn-express:server'); // 콘솔에 로그를 남기는 모듈
var http = require('http');

// process.env(환경변수) 객체에 PORT 속성이 있다면 이것을, 없으면 3000번 포트 사용
var port = normalizePort(process.env.PORT || '3000');

// 서버가 실행될 포트 설정
app.set('port', port);

var server = http.createServer(app);
server.listen(port);
server.on('error', onError); // 이벤트 등록
server.on('listening', onListening);

3. 미들웨어

  • 요청과 응답의 중간에 위치
  • app.use() 메서드에 의해 호출됨
  • 미들웨어 내에서 next() 메서드를 호출해야 다음 미들웨어로 넘어감

커스텀 미들웨어


// ...

app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'pug');

/* 커스텀 미들웨어 적용 */
app.use(function (req, res, next) {
  console.log(req.url, '안녕요?ㅎ');
  next();
});

/* morgan 미들웨어: 요청 정보를 콘솔에 기록 */
app.use(logger('dev'));

// ...

가독성이 좋지 않게 되지만 하나의 use에 여러 개의 미들웨어를 장착할 수 있음.

app.use('/', function (req, res, next) {
  console.log('첫 번째 미들웨어');
  next();
}, function (req, res, next) {
  console.log('두 번째 미들웨어');
  next();
}, function (req, res, next) {
  console.log('세 번째 미들웨어');
  next();
});

morgan

  • 요청 정보를 콘솔에 기록하는 미들웨어
  • 클라이언트가 접속 시 콘솔에 GET / 200 12.345ms 같은 로그 출력

/*** app.js ***/

// ...
var logger = require('morgan');

// ...
app.use(logger('dev')); // 주요 인자: dev, short, common, combined 등
// ...
  • logger() 메서드의 인자: dev, short, common, combined 등
    이 인자를 어떻게 주느냐에 따라 콘솔에 출력되는 로그가 달라짐
    • 개발 시: short나 dev
    • 배포 시: common이나 combined
  • 파일이나 데이터베이스에 로그를 남기려면 morgan 대신 winston 모듈 등을 사용

body-parser

  • 요청 들어온 본문(JSON, URL-encoded, Raw(버퍼 데이터), Text 등) 해석
  • multipart/form-data 같은 폼을 통해 전송된 데이터는 해석하지 못함
  • 폼 데이터나 AJAX 요청 데이터를 처리
  • Express 4.16.0 버전부터 body-parser의 일부 기능이 익스프레스에 내장됨
/*** app.js ***/

var express = require('express');

/* Express 4.16.0 버전 이후 내장된 body-parser 부분 */
app.use(express.json());
// app.use(bodyParser.raw()); // 본문이 버퍼 데이터일때 해석
// app.use(bodyParser.text()); // 본문이 텍스트 데이터일때 해석
app.use(express.urlencoded({ extended: false })); // false: querystring 모듈 사용, true: qs 모듈(querystring을 확장한 모듈) 사용

/* 위의 코드 작동 예시 */
// JSON 형식으로 { name: 'pengsu', study: 'nodejs' }를 본문으로 보낸다면 req.body 객체에 그대로 들어감
// URL-encoded 형식으로 name=pengsu&study=nodejs를 보낸다면 req.body 객체에 { name: 'ing-yeo', study: 'nodejs' }가 들어감

static

  • 정적인 파일 제공
  • 메서드의 인자로 정적 파일들이 담겨있는 폴더를 지정하면 됨 (기본: public 폴더)
    • 예: public/stylesheets/style.css 파일을 http://localhost:3000/stylesheets/styles.css 경로로 접근하도록 설정
    • 서버의 폴더 경로와 요청 경로가 다르므로 서버의 구조를 쉽게 파악할 수 없도록 함
/*** app.js ***/

// 정적 파일을 제공하는 폴더를 public 폴더로 지정 (/public/abc.png -> abc.png)
app.use(express.static(path.join(__dirname, 'public')));

// public 폴더 경로를 img로 지정 (/public/abc.png => /img/abc.png)
app.use('/img', express.static(path.join(__dirname, 'public')));
  • static 미들웨어는 정적 파일을 발견하면 응답으로 해당 파일을 전송
    • 이 경우 응답을 보냈기 때문에 다음에 나오는 라우터가 실행되지 않음
    • 파일을 찾지 못했다면 요청을 라우터로 넘김
    • 자체적으로 정적 파일 라우터 기능을 수행하므로 쓸데없는 미들웨어 작업을 하지 않도록 최대한 위쪽에 배치하는 것이 좋음
    • morgan 미들웨어 보다는 아래 쪽에서 호출하는 것이 좋음

4. Routing

  • 요청 경로에 따라 어떻게 처리할 것인지 설정
  • Router 객체를 사용하여 구현

기본적인 라우팅

라우팅 미들웨어는 첫 번째 인자로 주소를 받아서 특정 주소에 해당하는 요청이 왔을 때만 동작

app.use('/', function (req, res, next) {
  console.log('/ 주소의 요청일 때 실행됩니다. HTTP 메서드는 상관 없습니다.');
  next();
});
  • use() 메서드 대신 get(), post(), put(), patch(), delete() 같은 HTTP 메서드를 사용할 수도 있음
    • use() 메서드: 모든 HTTP 메서드에 대해 요청 주소만 일치할 때 실행
    • get(), post(), put(), patch(), delete() 메서드: 주소뿐만 아니라 HTTP 메서드까지 일치하는 요청일 때만 실행
app.use('/', function (req, res, next) {
  console.log('/ 주소의 요청일 때 실행됩니다. HTTP 메서드는 상관 없습니다.');
  next();
});
app.get('/', function (req, res, next) {
  console.log('GET 메서드 / 주소의 요청일 때만 실행됩니다.');
  next();
});
app.post('/data', function (req, res, next) {
  console.log('POST 메서드 /data 주소의 요청일 때만 실행됩니다.');
  next();
});

router 객체를 이용한 라우팅

router 객체를 만든 후 app.js 파일에서 이들을 미들웨어로 사용하여 라우팅

/*** app.js ***/

// ...
// routes 폴더에 있는 js 파일(router 객체)을 require
var indexRouter = require('./routes/index');
var usersRouter = require('./routes/users');
// ...

// ...
// 주소가 /로 시작하면 routes/index.js를 호출
app.use('/', indexRouter);

// 주소가 /users로 시작하면 routes/users.js를 호출
app.use('/users', usersRouter);
// ...

/*** routes/index.js ***/

var express = require('express');
var router = express.Router(); // router 객체 생성

// '/' 주소로 GET 요청 시 살행
router.get('/', function(req, res, next) {
  res.render('index', { title: 'Express' });
});

module.exports = router; // 라우터 모듈화


/*** routes/users.js ***/

var express = require('express');
var router = express.Router();

// '/users' 주소로 GET 요청 시 실행
router.get('/', function (req, res, next) {
  res.send('respond with a resource');
});

module.exports = router;

router 하나에 여러 개의 미들웨어를 여러 개 장착할 수 있음

router.get('/', middleWare1, middleWare2, middleWare3);

라우터에 연결된 나머지 미들웨어들을 건너뛸 때: next('route') 메서드 사용

router.get('/', function(req, res, next) {
  next('route'); // 연결된 미들웨어들을 건너뜀
}, function(req, res, next) {
  console.log('실행되지 않습니다.');
  next();
}, function(req, res, next) {
  console.log('실행되지 않습니다.');
  next();
});
profile
삽질의 기록들🐥

0개의 댓글