๋ณธ๋ฌธ์œผ๋กœ ๋ฐ”๋กœ๊ฐ€๊ธฐ

1. Middleware๋ž€?

1) HTPP ์š”์ฒญ์—์„œ ์‹œ์ž‘ํ•ด, ์ตœ์ข… ์‘๋‹ต์œผ๋กœ ๋ผ์šฐํŒ…ํ•˜๊ธฐ ์ „์˜ ์ค‘๊ฐ„ ๋‹จ๊ณ„๋ฅผ ๋งํ•œ๋‹ค

2) HTTP ์š”์ฒญ์ด ๋“ค์–ด์˜จ ์ˆœ๊ฐ„ ์‹œ์ž‘๋œ๋‹ค.

3) HTTP ์š”์ฒญ๊ณผ ์‘๋‹ต ์‚ฌ์ด์— ๋‹จ๊ณ„๋ณ„ ๋™์ž‘์„ ์ˆ˜ํ–‰ํ•ด์ฃผ๋Š” ํ•จ์ˆ˜๋‹ค.

4) HTTP ์š”์ฒญ ๊ฐ์ฒด๋ฅผ ์ฒ˜๋ฆฌํ•˜๊ฑฐ๋‚˜, ์‘๋‹ต ๊ฐ์ฒด๋ฅผ ์ฒ˜๋ฆฌ, ๋‹ค์Œ ๋ฏธ๋“ค์›จ์–ด๋ฅผ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๋‹ค.

5) HTTP ์‘๋‹ต์ด ์ตœ์ข…์ ์œผ๋กœ ๋งˆ๋ฌด๋ฆฌ๋  ๋•Œ๊นŒ์ง€, ๋ฏธ๋“ค์›จ์–ด ๋™์ž‘ ์‚ฌ์ดํด์ด ์‹คํ–‰๋œ๋‹ค.

6) ์ตœ์ข… ์‘๋‹ต์œผ๋กœ ๊ฐ€์ง€ ๋ชปํ•˜๊ฒŒ ์—ฐ๊ฒฐ์„ ๋Š์„ ์ˆ˜๋„ ์žˆ๋‹ค.

 

๋ฏธ๋“ค์›จ์–ด ์„ ์–ธํ•˜๊ธฐ

const middleware = (req, res, next) => { 
	next();  
 }

req, res, next๋ฅผ ๊ฐ€์ง„ ํ•จ์ˆ˜๋ฅผ ์ž‘์„ฑํ•˜๋ฉด ํ•ด๋‹น ํ•จ์ˆ˜๋Š” ๋ฏธ๋“ค์›จ์–ด๋กœ ๋™์ž‘ํ•  ์ˆ˜ ์žˆ๋‹ค.
- req:
HTTP ์š”์ฒญ์„ ์ฒ˜๋ฆฌํ•˜๋Š” ๊ฐ์ฒด, HTTP ์š”์ฒญ ์ •๋ณด๊ฐ€ ๋“ค์—ˆ์Œ
- res:
HTTP ์‘๋‹ต์„ ์ฒ˜๋ฆฌํ•˜๋Š” ๊ฐ์ฒด, ์š”์ฒญ์— ๋Œ€ํ•œ ์‘๋‹ต์„ ๋ฐ˜ํ™˜ํ•˜๋Š” ๊ฐ์ฒด
- next():
๋‹ค์Œ ๋ฏธ๋“ค์›จ์–ด๋ฅผ ์‹คํ–‰ํ•˜๋Š” ํ•จ์ˆ˜

 

2. ๋ฏธ๋“ค์›จ์–ด ์ž‘์„ฑ๋ฒ•

1. ๋ฏธ๋“ค์›จ์–ด๊ฐ€ ์—†์„ ๊ฒฝ์šฐ

response๊ฐ€ ์ฆ‰๊ฐ ๋ฐ˜์‘ํ•œ๋‹ค.

app.get("/", (req, res) => res.send("HomePage Accessed"));

2. ๋ฏธ๋“ค์›จ์–ด๋ฅผ ์„ค์ •ํ•  ๊ฒฝ์šฐ

3๊ฐœ์˜ ์ธ์ž(req, res, next)๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•œ๋‹ค.

const middlewareHome = (req, res, next) => { 
	console.log("๋ฏธ๋“ค์›จ์–ด ์ž‘๋™ ์™„๋ฃŒ"); 
	
    next();  
    // next()๋ฉ”์†Œ๋“œ๊ฐ€ ์—†๋‹ค๋ฉด ๋ฏธ๋“ค์›จ์–ด ์‚ฌ์ดํด์ด ๋ฉˆ์ถฐ, ํ™”๋ฉด์€ ๊ณ„์† loading ์ƒํƒœ๊ฐ€ ๋œ๋‹ค.
 } 

app.get("/", middlewareHome,
	(req, res) => res.send("HomePage Accessed"));

// ์‹คํ–‰ ์ˆœ์„œ
// 1. ๋ฏธ๋“ค์›จ์–ด ์ž‘๋™ ์™„๋ฃŒ
// 2. HomePage Accessed

3. ๋ชจ๋“  ํŽ˜์ด์ง€๊ฐ€ ์‚ฌ์šฉํ•˜๋Š” ๋ฏธ๋“ค์›จ์–ด๋ฅผ ์ƒ์„ฑํ•  ๊ฒฝ์šฐ

๋ฏธ๋“ค์›จ์–ด๋Š” ๋ผ์šฐํŠธ ์ด์ „์— ์ƒ์„ฑํ•ด์•ผ ์ž‘๋™ํ•œ๋‹ค.
๋ฏธ๋“ค์›จ์–ด๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์ฝ”๋“œ์ธ app.use()๊ฐ€ app.get()๋ณด๋‹ค ์„ ํ–‰๋˜์–ด์•ผ ํ•œ๋‹ค.

const globalMiddleware = (req, res, next) => {
		if (!isAdmin(req)) {
		next(new Error('Not Authorized'));
		return;
	}
	next();
}


app.use(auth);

app.get('/', responseHome);
app.get('/profile', responseProfile);

// ๋ฃจํŠธ ํŽ˜์ด์ง€, profile ํŽ˜์ด์ง€์— ๊ฐ๊ฐ ๋ผ์šฐํŠธ ํ•  ๋•Œ globalMiddleware๊ฐ€ ์ž‘๋™ํ•œ๋‹ค.

4. ๋ฏธ๋“ค์›จ์–ด ์„œ๋ธŒ ์Šคํƒ

use ๋‚˜ http method ํ•จ์ˆ˜์— ์—ฌ๋Ÿฌ ๊ฐœ์˜ ๋ฏธ๋“ค์›จ์–ด๋ฅผ ๋™์‹œ์— ์ ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค. ์ฃผ๋กœ ํ•œ ๊ฐœ์˜ ๊ฒฝ๋กœ์— ํŠน์ •ํ•ด์„œ ๋ฏธ๋“ค์›จ์–ด๋ฅผ ์ ์šฉํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉํ•œ๋‹ค. ์ „๋‹ฌ๋œ ์ธ์ž์˜ ์ˆœ์„œ ์ˆœ์œผ๋กœ ๋™์ž‘ํ•œ๋‹ค.

app.use(middleware1, middlware2, ...);

app.use('/admin', auth, adminRouter);

app.get('/', logger, (req, res, next) => {
	res.send('Hello Express');
})

 

3. ๋ฏธ๋“ค์›จ์–ด ์‚ฌ์šฉํ•˜๊ธฐ

middleware ๋Š” ์ ์šฉ๋˜๋Š” ์œ„์น˜์— ๋”ฐ๋ผ์„œ ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋ฏธ๋“ค์›จ์–ด, ๋ผ์šฐํ„ฐ ๋ฏธ๋“ค์›จ์–ด, ์˜ค๋ฅ˜์ฒ˜๋ฆฌ ๋ฏธ๋“ค์›จ์–ด๋กœ ๋ถ„๋ฅ˜ํ•  ์ˆ˜ ์žˆ๋‹ค. ํ•„์š”ํ•œ ๋™์ž‘ ๋ฐฉ์‹์— ๋”ฐ๋ผ ๋ฏธ๋“ค์›จ์–ด๋ฅผ ์ ์šฉํ•  ์œ„์น˜๋ฅผ ๊ฒฐ์ •ํ•˜์ž.

 

1) application middleware

use ๋‚˜ http method ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋ฏธ๋“ค์›จ์–ด๋ฅผ ์—ฐ๊ฒฐํ•  ์ˆ˜ ์žˆ๋‹ค. ๋ฏธ๋“ค์›จ์–ด๋ฅผ ๋ชจ๋“  ์š”์ฒญ์— ๊ณตํ†ต์ ์œผ๋กœ ์ ์šฉํ•˜๊ธฐ ์œ„ํ•œ ๋ฐฉ๋ฒ•์œผ๋กœ, HTTP ์š”์ฒญ์ด ๋“ค์–ด์˜จ ์ˆœ๊ฐ„๋ถ€ํ„ฐ ์ ์šฉ๋œ ์ˆœ์„œ๋Œ€๋กœ ๋™์ž‘ํ•œ๋‹ค.

app.use((req, res, next) => {
	console.log(`Request ${req.path}`);
	next();
});

app.use(auth);

app.get('/', (req, res, next) => {
	res.send('Hello Express');
});

 

2) router middleware

router ๊ฐ์ฒด์— ๋ฏธ๋“ค์›จ์–ด๊ฐ€ ์ ์šฉ๋˜๋Š” ๊ฒƒ ์ด์™ธ์—๋Š” ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋ฏธ๋“ค์›จ์–ด์™€ ์‚ฌ์šฉ ๋ฐฉ๋ฒ•์€ ๋™์ผํ•˜๋‹ค. ํŠน์ • ๊ฒฝ๋กœ์˜ ๋ผ์šฐํŒ…์—๋งŒ ๋ฏธ๋“ค์›จ์–ด๋ฅผ ์ ์šฉํ•˜๊ธฐ ์œ„ํ•œ ๋ฐฉ๋ฒ•์ด๋‹ค. app ๊ฐ์ฒด์— ๋ผ์šฐํ„ฐ๊ฐ€ ์ ์šฉ๋œ ์ดํ›„๋กœ ์ˆœ์„œ๋Œ€๋กœ ๋™์ž‘ํ•œ๋‹ค.

router.use(auth);  // 3

router.get('/', (req, res, next) => { // 4
	res.send('Hello Router');
});

app.use((req, res, next) => {   // 1
	console.log(`Request ${req.path}`);
	next();
});

app.use('/admin', router);   // 2

 

3) error handleing middleware

์˜ค๋ฅ˜์ฒ˜๋ฆฌ ๋ฏธ๋“ค์›จ์–ด๋Š” ์ผ๋ฐ˜์ ์œผ๋กœ ๊ฐ€์žฅ ๋งˆ์ง€๋ง‰์— ์œ„์น˜ํ•œ๋‹ค. ๋‹ค๋ฅธ ๋ฏธ๋“ค์›จ์–ด๋“ค๊ณผ๋Š” ๋‹ฌ๋ฆฌ err, req, res, next ๋„ค ๊ฐ€์ง€ ์ธ์ž๋ฅผ ๊ฐ€์ง€๋ฉฐ, ์•ž์„  ๋ฏธ๋“ค์›จ์–ด์—์„œ next ํ•จ์ˆ˜์— ์ธ์ž๊ฐ€ ์ „๋‹ฌ๋˜๋ฉด, ์ค‘๊ฐ„ ๋ฏธ๋“ค์›จ์–ด๋“ค์€ ๋›ฐ์–ด๋„˜๊ณ  ์˜ค๋ฅ˜์ฒ˜๋ฆฌ ๋ฏธ๋“ค์›จ์–ด๊ฐ€ ๋ฐ”๋กœ ์‹คํ–‰๋œ๋‹ค.

app.use((req, res, next) => {         // 1
	if (!isAdmin(req)) {
	next(new Error('Not Authorized'));
	return;
}
	next();
});

app.get('/', (req, res, next) => {    // ๊ฑด๋„ˆ๋”
	res.send('Hello Express');
});

app.use((err, req, res, next) => {    // 2
	res.send('Error Occurred');
});

 

๊ฐ€์žฅ ๋งˆ์ง€๋ง‰ ๋ฏธ๋“ค์›จ์–ด๋กœ ์˜ค๋ฅ˜ ์ฒ˜๋ฆฌ ๋ฏธ๋“ค์›จ์–ด๋ฅผ ์ ์šฉํ•˜๋ฉด, ๋ชจ๋“  ๋ผ์šฐํŒ…์— ๊ณตํ†ต์ ์ธ ์˜ค๋ฅ˜์ฒ˜๋ฆฌ ๋กœ์ง์„ ์ ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

 

app.use((err, req, res, next) => {
	res.status(500);
	res.json({
		result: 'fail',
		error: err.message,
	});
});

 

์ •์˜๋˜์ง€ ์•Š์€ ๋ผ์šฐํŒ…์— 404 ์˜ค๋ฅ˜ ์ฒ˜๋ฆฌํ•˜๊ธฐ

๋ชจ๋“  ๋ผ์šฐํŒ…์ด ์ ์šฉ๋œ ์ดํ›„์— ์‚ฌ์šฉ๋˜๋Š” ๋ฏธ๋“ค์›จ์–ด๋Š” ์„ค์ •๋œ ๊ฒฝ๋กœ๊ฐ€ ์—†๋Š” ์š”์ฒญ์„ ์ฒ˜๋ฆฌํ•˜๋Š” Route Handler๋กœ ๋™์ž‘ํ•œ๋‹ค. Express.js ๋Š” ๊ธฐ๋ณธ์ ์ธ 404 ํŽ˜์ด์ง€๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ์ง€๋งŒ, ์ง์ ‘ ์ฒ˜๋ฆฌ๊ฐ€ ํ•„์š” ํ•œ ๊ฒฝ์šฐ ์ด์™€ ๊ฐ™์€ Route Handler๋ฅผ ์ถ”๊ฐ€ํ•ด์•ผํ•œ๋‹ค. 

app.use((req, res, next) => {
	res.status(404);
	res.send({ 
		result: 'fail', 
		error: `Page not found ${req.path}`
	});
});

 

4) ํ•จ์ˆ˜ํ˜• ๋ฏธ๋“ค์›จ์–ด

ํ•˜๋‚˜์˜ ๋ฏธ๋“ค์›จ์–ด๋ฅผ ์ž‘์„ฑํ•˜๊ณ , ์ž‘๋™ ๋ชจ๋“œ๋ฅผ ์„ ํƒํ•˜๋ฉด์„œ ์‚ฌ์šฉํ•˜๊ณ  ์‹ถ์„ ๊ฒฝ์šฐ, API๋ณ„๋กœ ์‚ฌ์šฉ์ž์˜ ๊ถŒํ•œ์„ ๋‹ค๋ฅด๊ฒŒ ์ œํ•œํ•˜๊ณ  ์‹ถ์€ ๊ฒฝ์šฐ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค. ํ•จ์ˆ˜ ์‹คํ–‰ ์‹œ ๋ฏธ๋“ค์›จ์–ด์˜ ๋™์ž‘์ด ๊ฒฐ์ •๋˜๋Š” ๋ฐฉ์‹์œผ๋กœ, ๋™์ผํ•œ ๋กœ์ง์— ์„ค์ •๊ฐ’๋งŒ ๋‹ค๋ฅด๊ฒŒ ๋ฏธ๋“ค์›จ์–ด๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์‹ถ์„ ๊ฒฝ์šฐ์— ํ™œ์šฉ๋œ๋‹ค.

const auth = (memberType) => {
	return (req, res, next) => {
		if (!checkMember(req, memberType)) {
			next(new Error(`member not ${memberType}`));
			return;
		}
	next();
	}
}

app.use('/admin', auth('admin'), adminRouter);
app.use('/users', auth('member'), userRouter);
๋ฐ˜์‘ํ˜•