StrongLoop / IBM์ ์ํด ์ ๊ณต์ด ๋ฒ์ญ.
์ด ๋ฌธ์๋ ์๋ฌธํ ๋ฌธ์์ ๋นํด ๋ ์ค๋๋ ๋ฒ์ ์ผ ์๋ ์์ต๋๋ค. ์ต์ ์ ๋ฐ์ดํธ๋ฅผ ํ์ธํ๋ ค๋ฉด ์๋ฌธํ ๋ฌธ์๋ฅผ ์ฐธ์กฐํ์ญ์์ค.๋ค๋ฅธ ๋ฏธ๋ค์จ์ด ํจ์์ ๋์ผํ ๋ฐฉ๋ฒ์ผ๋ก ์ค๋ฅ ์ฒ๋ฆฌ ๋ฏธ๋ค์จ์ด ํจ์๋ฅผ ์ ์ํ ์ ์์ง๋ง,
์ค๋ฅ ์ฒ๋ฆฌ ํจ์๋ 3๊ฐ๊ฐ ์๋ 4๊ฐ์ ์ธ์, ์ฆ (err, req, res, next)
๋ฅผ
๊ฐ๋๋ค๋ ์ ์ด ๋ค๋ฆ
๋๋ค. ์๋ฅผ ๋ค๋ฉด ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
app.use(function(err, req, res, next) {
console.error(err.stack);
res.status(500).send('Something broke!');
});
์ค๋ฅ ์ฒ๋ฆฌ ๋ฏธ๋ค์จ์ด๋ ๋ค๋ฅธ app.use()
๋ฐ ๋ผ์ฐํธ ํธ์ถ์ ์ ์ํ ํ์ ๋ง์ง๋ง์ผ๋ก ์ ์ํด์ผ ํ๋ฉฐ, ์๋ฅผ ๋ค๋ฉด ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
var bodyParser = require('body-parser');
var methodOverride = require('method-override');
app.use(bodyParser());
app.use(methodOverride());
app.use(function(err, req, res, next) {
// logic
});
๋ฏธ๋ค์จ์ด ํจ์ ๋ด๋ถ๋ก๋ถํฐ์ ์๋ต์ HTML ์ค๋ฅ ํ์ด์ง, ๋จ์ํ ๋ฉ์์ง ๋๋ JSON ๋ฌธ์์ด ๋ฑ ์ฌ๋ฌ๋ถ์ด ์ ํธํ๋ ๋ชจ๋ ํ์์ผ ์ ์์ต๋๋ค.
์กฐ์ง์ (๋ฐ ์์ ๋ ๋ฒจ ํ๋ ์์ํฌ) ๋ชฉ์ ์ ์ํด, ์ฌ๋ฌ ์ค๋ฅ ์ฒ๋ฆฌ
๋ฏธ๋ค์จ์ด ํจ์๋ฅผ ์ ์ํ ์ ์์ผ๋ฉฐ, ์ด๋ ์ผ๋ฐ์ ์ธ ๋ฏธ๋ค์จ์ด ํจ์๋ฅผ ์ ์ํ ๋์
๋งค์ฐ ๋น์ทํฉ๋๋ค. ์๋ฅผ ๋ค์ด XHR
๋ฅผ ์ด์ฉํ ์์ฒญ ๋ฐ
๊ทธ๋ ์ง ์์ ์์ฒญ์ ๋ํ ์ค๋ฅ ์ฒ๋ฆฌ๋ฅผ ์ ์ํ๋ ค๋ ๊ฒฝ์ฐ, ๋ค์๊ณผ ๊ฐ์ ๋ช
๋ น์ ์ฌ์ฉํ ์ ์์ต๋๋ค.
var bodyParser = require('body-parser');
var methodOverride = require('method-override');
app.use(bodyParser());
app.use(methodOverride());
app.use(logErrors);
app.use(clientErrorHandler);
app.use(errorHandler);
์ด ์์์ ์ผ๋ฐ logErrors
๋ ์์ฒญ ๋ฐ ์ค๋ฅ ์ ๋ณด๋ฅผ stderr
์
๊ธฐ๋กํ ์๋ ์์ผ๋ฉฐ, ์๋ฅผ ๋ค๋ฉด ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
function logErrors(err, req, res, next) {
console.error(err.stack);
next(err);
}
๋ํ ์ด ์์์ clientErrorHandler
๋ ๋ค์๊ณผ ๊ฐ์ด ์ ์๋๋ฉฐ, ์ด ๊ฒฝ์ฐ ์ค๋ฅ๋ ๋ช
์์ ์ผ๋ก ๊ทธ ๋ค์ ํญ๋ชฉ์ผ๋ก ์ ๋ฌ๋ฉ๋๋ค.
function clientErrorHandler(err, req, res, next) {
if (req.xhr) {
res.status(500).send({ error: 'Something failed!' });
} else {
next(err);
}
}
โ๋ชจ๋ ์ค๋ฅ๋ฅผ ์ฒ๋ฆฌํ๋(catch-all)โ errorHandler
ํจ์๋ ๋ค์๊ณผ ๊ฐ์ด ๊ตฌํ๋ ์ ์์ต๋๋ค.
function errorHandler(err, req, res, next) {
res.status(500);
res.render('error', { error: err });
}
next()
ํจ์๋ก ์ด๋ ํ ๋ด์ฉ์ ์ ๋ฌํ๋ ๊ฒฝ์ฐ('route'
๋ผ๋ ๋ฌธ์์ด ์ ์ธ), Express๋ ํ์ฌ์ ์์ฒญ์ ์ค๋ฅ๊ฐ ์๋ ๊ฒ์ผ๋ก ๊ฐ์ฃผํ๋ฉฐ, ์ค๋ฅ ์ฒ๋ฆฌ์ ๊ด๋ จ๋์ง ์์ ๋๋จธ์ง ๋ผ์ฐํ
๋ฐ ๋ฏธ๋ค์จ์ด ํจ์๋ฅผ ๊ฑด๋๋๋๋ค. ์ด๋ฌํ ์ค๋ฅ๋ฅผ ์ด๋ป๊ฒ๋ ์ฒ๋ฆฌํ๊ธฐ ์ํ๋ ๊ฒฝ์ฐ, ๋ค์ ์น์
์ ์ค๋ช
๋ ๊ฒ๊ณผ ๊ฐ์ด ์ค๋ฅ ์ฒ๋ฆฌ ๋ผ์ฐํธ๋ฅผ ์์ฑํด์ผ ํฉ๋๋ค.
์ฌ๋ฌ ์ฝ๋ฐฑ ํจ์๋ฅผ ๊ฐ๋ ๋ผ์ฐํธ ํธ๋ค๋ฌ๊ฐ ์๋ ๊ฒฝ์ฐ์๋ route
๋งค๊ฐ๋ณ์๋ฅผ ์ฌ์ฉํ์ฌ ๊ทธ ๋ค์์ ๋ผ์ฐํธ ํธ๋ค๋ฌ๋ก ๊ฑด๋๋ธ ์ ์์ต๋๋ค. ์๋ฅผ ๋ค๋ฉด ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
app.get('/a_route_behind_paywall',
function checkIfPaidSubscriber(req, res, next) {
if(!req.user.hasPaid) {
// continue handling this request
next('route');
}
}, function getPaidContent(req, res, next) {
PaidContent.find(function(err, doc) {
if(err) return next(err);
res.json(doc);
});
});
์ด ์์์ getPaidContent
ํธ๋ค๋ฌ์ ์คํ์ ๊ฑด๋๋ฐ์ง๋ง, /a_route_behind_paywall
์ ๋ํ app
๋ด์ ๋๋จธ์ง ํธ๋ค๋ฌ๋ ๊ณ์ํ์ฌ ์คํ๋ฉ๋๋ค.
next()
๋ฐ next(err)
์ ๋ํ ํธ์ถ์ ํ์ฌ์ ํธ๋ค๋ฌ๊ฐ ์๋ฃ๋์๋ค๋ ๊ฒ๊ณผ ํด๋น ํธ๋ค๋ฌ์ ์ํ๋ฅผ ํ์ํฉ๋๋ค. next(err)
๋ ์์ ์ค๋ช
๋ ๊ฒ๊ณผ ๊ฐ์ด ์ค๋ฅ๋ฅผ ์ฒ๋ฆฌํ๋๋ก ์ค์ ๋ ํธ๋ค๋ฌ๋ฅผ ์ ์ธํ ์ฒด์ธ ๋ด์ ๋๋จธ์ง ๋ชจ๋ ํธ๋ค๋ฌ๋ฅผ ๊ฑด๋๋๋๋ค.
Express๋ ๋ด์ฅ๋ ์ค๋ฅ ํธ๋ค๋ฌ์ ํจ๊ป ์ ๊ณต๋๋ฉฐ, ๋ด์ฅ ์ค๋ฅ ํธ๋ค๋ฌ๋ ์ฑ์์ ๋ฐ์ํ ์ ์๋ ๋ชจ๋ ์ค๋ฅ๋ฅผ ์ฒ๋ฆฌํฉ๋๋ค. ์ด๋ฌํ ๊ธฐ๋ณธ ์ค๋ฅ ์ฒ๋ฆฌ ๋ฏธ๋ค์จ์ด ํจ์๋ ๋ฏธ๋ค์จ์ด ํจ์ ์คํ์ ๋์ ์ถ๊ฐ๋ฉ๋๋ค.
next()
๋ก ์ค๋ฅ๋ฅผ ์ ๋ฌํ์ง๋ง ์ค๋ฅ ํธ๋ค๋ฌ์์ ํด๋น ์ค๋ฅ๋ฅผ
์ฒ๋ฆฌํ์ง ์๋ ๊ฒฝ์ฐ, ๊ธฐ๋ณธ ์ ๊ณต ์ค๋ฅ ํธ๋ค๋ฌ๊ฐ ํด๋น ์ค๋ฅ๋ฅผ ์ฒ๋ฆฌํ๋ฉฐ, ํด๋น ์ค๋ฅ๋
ํด๋ผ์ด์ธํธ์ ์คํ ์ถ์ ๊ณผ ํจ๊ป ๊ธฐ๋ก๋ฉ๋๋ค. ์คํ ์ถ์ ์ ํ๋ก๋์
ํ๊ฒฝ์ ํฌํจ๋์ด ์์ง ์์ต๋๋ค.
ํ๋ก๋์
๋ชจ๋์์ ์ฑ์ ์คํํ๋ ค๋ฉด ํ๊ฒฝ ๋ณ์ NODE_ENV
๋ฅผ production
์ผ๋ก ์ค์ ํ์ญ์์ค.
์๋ต์ ๊ธฐ๋ก์ ์์ํ ํ์ ์ค๋ฅ๊ฐ ์๋ next()
๋ฅผ
ํธ์ถํ๋ ๊ฒฝ์ฐ(์: ์๋ต์ ํด๋ผ์ด์ธํธ๋ก ์คํธ๋ฆฌ๋ฐํ๋ ์ค์ ์ค๋ฅ๊ฐ
๋ฐ์ํ๋ ๊ฒฝ์ฐ), Express์ ๊ธฐ๋ณธ ์ค๋ฅ ํธ๋ค๋ฌ๋ ํด๋น ์ฐ๊ฒฐ์ ๋ซ๊ณ
ํด๋น ์์ฒญ์ ์ฒ๋ฆฌํ์ง ์์ต๋๋ค.
๋ฐ๋ผ์ ์ฌ์ฉ์ ์ ์ ์ค๋ฅ ํธ๋ค๋ฌ๋ฅผ ์ถ๊ฐํ ๋, ํค๋๊ฐ ์ด๋ฏธ ํด๋ผ์ด์ธํธ๋ก ์ ์ก๋ ๊ฒฝ์ฐ์๋ ๋ค์๊ณผ ๊ฐ์ด Express ๋ด์ ๊ธฐ๋ณธ ์ค๋ฅ ์ฒ๋ฆฌ ๋ฉ์ปค๋์ฆ์ ์์ํด์ผ ํฉ๋๋ค:
function errorHandler(err, req, res, next) {
if (res.headersSent) {
return next(err);
}
res.status(500);
res.render('error', { error: err });
}
๋ง์ฝ next()
๋ฅผ ์ฌ๋ฌ๋ถ์ ์ฝ๋์์ ์ฌ๋ฌ ๋ฒ ํธ์ถํ๋ค๋ฉด, ์ฌ์ฉ์ ์ ์ ์ค๋ฅ ํธ๋ค๋ฌ๊ฐ ์์์๋ ๋ถ๊ตฌํ๊ณ ๊ธฐ๋ณธ ์ค๋ฅ ํธ๋ค๋ฌ๊ฐ ๋ฐ๋๋ ์ ์์์ ์ฃผ์ํ์ญ์์ค.