미들웨어(middleware)란 클라이언트에 의한 요청과 응답 그 중간에서 거쳐가는 함수들을 의미한다.
미들웨어 함수는 요청 객체(request)와 응답 객체(response)의 요청-응답 주기 사이에서 실행되어 처리되는 함수에 대한 액세스를 갖는다.
출처: https://expressjs.com/ko/guide/writing-middleware.html
const express = require("express");
const app = express();
app.get("/", (req, res, next) => {
next();
});
app.listen(3000);
미들웨어 함수의 호출 요소는 다음과 같다.
app
의 첫번째 메서드로 HTTP의 메서드를 입력한다.(ex. get
, post
, put
, delete
등)
이후 첫번째 파라미터로 요청 url을 입력 받는다. 미들웨어는 해당 요청 url과 같을 경우에만 미들웨어를 실행하게 된다.
두번째 파라미터부터는 실제로 처리될 미들웨어 함수를 입력받는다.
미들웨어 함수는 첫번째 인자로 요청 객체(request), 두번째 인자로 응답 객체(response), 세번째 인자로 다음 미들웨어 함수를 실행시킬 next
함수가 할당된다.
예를 들어서 클라이언트의 요청 시각을 로깅하는 어플리케이션을 만들면 다음과 같다.
var express = require('express');
var app = express();
var requestTime = function (req, res, next) {
req.requestTime = Date.now();
next();
};
app.use(requestTime);
app.get('/', function (req, res) {
var responseText = 'Hello World!';
responseText += 'Requested at: ' + req.requestTime + '';
res.send(responseText);
});
app.listen(3000);
우선 requestTime
미들웨어 함수를 작성하고 해당 함수 내부에서 요청 객체인 req
의 requestTime
프로퍼티를 Date.now()
로 요청 당시 시간으로 할당한다.
이후 app.use(requestTime)
를 우선적으로 작성하여 미들웨어 함수를 실행시킨다.
이후 app.get("/", (req,res) =? { ... })
을 통해 /
라우팅 url을 통해 get
HTTP 메서드가 요청될때 req.requestTime
을 send
하도록 작성한다,.
이때 HTTP 메서드가 아닌 use
를 사용하게 되면 해당 미들웨어 함수는 HTTP 메서드에 상관없이 실행된다.
또한 use
는 get
과 다르게 요청 url을 따로 지정해주지 않아도 되는데 이 경우 url에 상관없이 매번 실행된다.
미들웨어는 다음과 같은 유형들이 존재한다.
app.use()
및 app.METHOD()
를 이용해 app 오브젝트에 할당한다.
미들웨어를 어플리케이션 영역에서 지정한 url에 따라 처리 가능하게 하도록 한다.
app.use('/user/:id', function(req, res, next) {
console.log('Request URL:', req.originalUrl);
next();
}, function (req, res, next) {
console.log('Request Type:', req.method);
next();
});
상기한 미들웨어는 '/user/:id'
에 따른 라우팅에만 실행되며 두번째 인자로 온 미들웨어 함수 내에서 next()
구문이 실행되면서 다음 미들웨어를 실행하게 된다.
var router = express.Router();
require
로 불러온 express
객체는 기본적으로 라우터를 컨트롤하기 위한 객체를 생성하는 메서드가 존재한다.
var app = express();
var router = express.Router();
router.use(function (req, res, next) {
console.log('Time:', Date.now());
next();
});
router.use('/user/:id', function(req, res, next) {
console.log('Request URL:', req.originalUrl);
next();
}, function (req, res, next) {
console.log('Request Type:', req.method);
next();
});
router.get('/user/:id', function (req, res, next) {
if (req.params.id == 0) next('route');
else next();
}, function (req, res, next) {
res.render('regular');
});
router.get('/user/:id', function (req, res, next) {
console.log(req.params.id);
res.render('special');
});
app.use('/', router);
이는 라우팅을 디렉토리별로 설정하여 코드를 라우팅 url마다 적용시키는데 도움을 준다.
예를들어 파일을 다음과 같이 분리시킬 수 있다.
//...index.js
const http = require("http");
const express = require("express");
const app = express();
const route = require("./routes/route.js");
app.use("/route", route);
app.use((req, res, next) => {
res.status(404).sendFile(path.join(__dirname, "views", "404.html"));
});
const server = http.createServer(app);
server.listen(3000);
//...route.js
const express = require("express");
const router = express.Router();
router.get("/", (req, res, next) => {
console.log("/route");
});
router.post("/inner", (req, res, next) => {
console.log("/route/inner");
});
module.exports = router;
라우팅 전용 미들웨어 함수 그룹을 따로 파일을 분리한 후 해당 라우트 미들웨어를 app
에서 불러온다.
이후 app.use("/route", route);
를 통해 path
와 route
를 미들웨어로 적용시킨다.
이럴경우 route
미들웨어는 기본적으로 /route
경로에 의해서 실행된다.
app.use(function(err, req, res, next) {
console.error(err.stack);
res.status(500).send('Something broke!');
});
오류 처리 미들웨어의 경우 일반적으로 가장 마지막에 작성된다.
또한 오류 처리 미들웨어는 미들웨어 함수의 인자값으로 4개의 인자를 입력받는다.
미들웨어 함수의 첫번째 인자로서 err
객체를 받는다.
일반적인 미들웨어 함수의 경우, next
를 사용하지 않을 경우에 인자에서 생략하는 케이스도 존재하지만 오류 처리 미들웨어는 인자값을 4개로 고정하여야 정상적인 취급이 가능하므로 사용하지 않더라도 next
를 생략해서는 안된다.
express에서 기본적으로 모듈로서 적용되는 함수들을 의미한다.
대표적으로 정적 파일 제공에 관한 미들웨어인 express.static(root, [options])
등이 존재한다.
Express 앱에 기능을 추가하려면 npm을 통해 인스톨 후 써드파티 미들웨어를 사용한다.