Express.js : 미들웨어

김종현·2023년 4월 4일
0

Node.js

목록 보기
6/8

미들웨어

  1. 특징
    -HTTP 요청이 들어온 순간부터 실행된다.
    -HTTP request-response 사이클 안에서 순차적으로 HTTP 요청 처리를 하거나 응답 마무리 혹은 다음 미들웨어를 실행 가능. HTTP 응답이 마무리 될 때 까지 이런 동작 사이클이 실행 됨.
    -이 사이클 안에서 routing handler 함수가 가지고 있는 request 객체, response 객체, next 함수에 대한 접근이 가능한 함수.
    -등록 순서에 따라 실행되기 때문에 주의해야한다 : 큐에 아이템을 등록한다는 느낌으로 코드를 작성하면 편하다
    -Express 앱 내부에서 request-response 사이클이 진행될 때마다 반드시 실행되어야 하는 코드들을 정의하기에 적합하다
    -어떠한 코드도 실행 가능하다.
    -request, response 객체 수정이 가능하다.
    -middleware는 global 단위(모든 PATH), PATH 단위로 유연하게 등록이 가능하다

2. 작성법

-req, res, next를 가진 함수를 작성시 해당 함수는 미들웨어로 동작.
-Route Handler도 미들웨어의 한 종류.
-Route Handler는 라우팅 함수(get/post/put/delete등)에 적용된 미들웨어로 일반적인 미들웨어와 다르게 path parameter를 사용 가능.

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

const auth = (req, res, next) => {
  if(!isAdmin(req)) {
    res.send("not identified");
    return;
  }
  next();
}

-next() 함수가 호출되지 않으면 미들웨어 사이클이 멈추게 되므로 주의해야한다.

적용되는 위치에 따라서 어플리케이션/라우터/오류처리 미들웨어로 분류 가능하다.
필요한 동작 방식에 따라 미들웨어를 적용할 위치를 결정해야한다.

3. 어플리케이션 미들웨어

-app 객체에 use나 http 메소드를 사용하는 형태는 어플리케이션 미들웨어.
-app.use 나 app.http 메소드를 사용하여, 미들웨어를 설정한 path 대로 처리가능하게 할 수 있다.
-모든 요청에 공통적으로 미들웨어를 적용.
-HTTP 요청이 들어온 순간부터 적용된 순서대로 동작한다.

-app.http메소드 : ex) app.get() , app.post() , … : 얻기 get 작성 post 제거 delete...

//동작 순서는 번호로 표기.
// 화살표 쳐진 부분이 미들웨어 적용 부분
①
app.use→(req, res, next) =>{
  console.log(`Request ${req.path}`);
  next();
});
②
app.use(→auth←);

//http 요청은 여기서 받음
③
app.get('/', (req,res,next)=>{
  res.send('hello there');
});

-특정 경로나, 특정 http 메소드에 대해서 미들웨어를 적용할 수 있다.

// 모든 /user/:id 요청에 대해 작동
app.use('/user/:id', function (req, res, next) {
console.log('Request Type:', req.method);
next();
});
// /user/:id인 GET 요청에 대해서만 응답
app.get('/user/:id', function (req, res, next) {
res.send('USER');
});

-하나의 경로에 여러개의 미들웨어를 순차적으로 적용할 수 있다.

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

4. 라우터 미들웨어

-Router객체를 이용해, 특정 최상위(루트) url을 기점으로 기능이나 로직별로 경로를 나누는 라우팅을 적용할 수 있다.
-var router = express.Router()로 Router 객체를 생성한 뒤에 app.use()를 사용해 마운트 시켜야지만 사용가능하다.

-특정 경로의 라우팅에만 미들웨어를 적용하는 방법 : 라우팅을 통해 각 경로마다 기능과 로직을 달리한다.
-ex) /users 경로에는 회원가입과 로그인에 대해 요청받을 것이므로 인증을 거치는 미들웨어를 추가한다.

-app.use()에서 지정한 경로와 같은 것이 들어온다면 모두 적용시켜버리기 때문에 중복이 될 가능성이 있다.
-예를 들어 app.use('/apple', ...) 이 있다면 /apple, /apple/images, /apple/images/news 등 하위 경로에 모두 적용시켜 버린다

-router 객체에 미들웨어가 적용되는 것 외에 어플리케이션 미들웨어와 동일하게 사용한다.

-app 객체에 라우터가 적용되는 것이 먼저고 이후에 순서대로 동작함.

//동작 순서는 번호로 표기.
// 화살표 쳐진 부분이 미들웨어 적용 부분

const { Router } = require('express');
const router = Router();

//3,4 에서 라우터는 선언된 상태고 라우터에 미들웨어도 연결되었음
③ 
router.use(→auth←);
//http 요청 받음
④
router.get('/', (req,res,next)=>{
  res.send('hello there');
});
// app.use에 연결된 어플리케이션 미들웨어(1번)가 먼저 수행
②
app.use→(req, res, next) =>{
  console.log(`Request ${req.path}`);
  next();
});
//app 객체에 admin path로 라우터 적용. 
①
app.use('admin', →router←);

5. 미들웨어 서브스택

-use나 http method 함수에 여러 개의 미들웨어를 동시에 적용 가능함
-주로 한개의 경로에 특정해서 미들웨어를 적용하기 위해 사용
-전달된 인자의 순서 순으로 동작

//미들웨어 1 그다음 2 순으로 동작
app.use(→middleware1←, →middleware2←, ...);
        
app.use('/admin', →auth←, adminRouter);

app.get('/', →logger←, (req,res,next)=>{
  res.send('hello there');
});

6. 오류처리 미들웨어

-미들웨어나 라우터 헨들러에서 작업을 수행할 때 에러가 발생할 경우 해당 에러를 catch해서 오류에 대해 어떻게 처리할 것인지를 정의하는 미들웨어이다.
-항상 4개의 파라미터가 필요하다 : ( err, req, res, next ) err 매개변수가 가장 앞에 있다.
-일반적으로 가장 마지막에 위치하는 미들웨어.
-다른 미들웨어가 next()에 인자를 전달(에러를 넘기면)하면 중간의 다른 미들웨어는 뛰어 넘고 오류 처리 미들웨어가 실행된다.
-오류처리 미들웨어가 없으면 next로 에러를 넘겨주었을 때, 처리할 부분이 없어 서버가 죽는다. 필수작성.

①
app.use(err, req, res, next) => {
  if(!isAdin(req)) {
    next(new Error('not identified'));
    return;
  }
  next();
});

app.get('/', (req, res, next) =>{
  res.send('hello there');
});
//1번에서 에러를 next로 넘겼으니 중간 건너뛰고 2번 실행
//app.use를 작성 후 파라미터, res.send를 사용.
②
app.use(err, req, res, next) => {
  res.status(500).send('Error !!');
});

7. 함수형 미들웨어

-하나의 미들웨어를 작성하고 작동 모드를 선택하면서 사용하고 싶을 경우 미들웨어를 함수형으로 작성하여 사용할 수 있음.
-ex) API별로 사용자의 권한을 다르게 제한하고 싶은 경우
-미들웨어에 값을 설정하고 싶을 때 함수형으로 작성.

//auth 실행시 파라미터에 따라 동작이 결정됨.
const auth = (memberType) => {
  //화살표 함수식으로 작성하여 파라미터를 넣을 수 있게 만들고 그 리턴 안에 미들웨어를 작성
  reutrn (req, res, next) => {
    //파라미터를 확인하는 함수를 통해 멤버 타입이 일치하지 않으면 에러 처리
    if(!memberCheck(req, memberType)) {
      next(new Error(`this member is not ${memberType}`));
      return;
    }
    next();
  }
}
//동일 로직 다른 설정값(파라미터)
app.use('/admin', auth('admin'), adminRouter);

app.use('/users', auth('member'), userRouter);

-auth 함수는 미들웨어를 반환하는 함수.
-auth 실행시 미들웨어의 동작이 결정되는 방식으로 작성되어 있음.
-일반적으로 동일한 로직에 설정 값만 다르게 미들웨어를 사용하고 싶을 경우에 활용 됨.

8.써드파티 미들웨어

-앱에 기능을 추가할 때 사용하는 미들웨어들. 이미 만들어져 라이브러리로 제공됨.
-Express.js 홈페이지나 npm 온라인 저장소에서 검색 가능.. ex) cors, multer, passport
-필요한 기능을 위한 Node.js 모듈을 설치한 후, 애플리케이션 레벨 또는 라우터 레벨에서 해당 모듈을 앱에 로드한다. npm을 추가하여 사용할 수 있다.
ex ) body-parser

profile
나는 나의 섬이다.

0개의 댓글