tech.junha.kr

[Express 미들웨어] 미들웨어란? 미들웨어 작성법

1. Middleware란?

  1. HTPP 요청에서 시작해, 최종 응답으로 라우팅하기 전의 중간 단계를 말한다

  2. HTTP 요청이 들어온 순간 시작된다.

3) HTTP 요청과 응답 사이에 단계별 동작을 수행해주는 함수다.

  1. HTTP 요청 객체를 처리하거나, 응답 객체를 처리, 다음 미들웨어를 실행할 수 있다.

  2. HTTP 응답이 최종적으로 마무리될 때까지, 미들웨어 동작 사이클이 실행된다.

  3. 최종 응답으로 가지 못하게 연결을 끊을 수도 있다.

미들웨어 선언하기

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);