1. Middleware란?

 

  미들웨어는 (req, res, next) 세 개의 파라미터를 가지는 함수이다.

  여기에서 next 인자는 여러 개의 함수를 연결할 수 있도록 하는 함수이다.

  간단한 예시 코드를 살펴보자.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 서버 시간이 오전이면 true를 반환, 그렇지 않으면 false를 반환
function isMorning() {...}
 
app.get("/hello",
  // middleware #1
  (req, res, next) => {
    if (isMorning()) {
      res.send("morning");
    } else {
      next();
    }
  },
  // middleware #2: isMorning()이 false일 때 next()에 의해 실행되는 미들웨어
  (req, res, next) => {
    res.send("afternoon");
  }
);
cs

 

  여기서는 '/hello' 경로를 처리하기 위해 두 개의 미들웨어 함수를 연결했다.

  next()를 사용하여 첫 번째 미들웨어에서 두 번째 미들웨어로 제어를 전달했음을 알 수 있다.

  이러한 미들웨어 함수는 경로간에 공통 코드를 공유하는 데 유용하다.

 

 

 

2. EX1 : 특정 경로에 대한 사용자 인증

 
  여기에서는 사용자가 인증되었을 때만 next()를 호출하는 미들웨어를 만들었다.

  미들웨어는 두 경로에서 공유되고있다. 사용자가 인증되지 않은 경우 next()를 호출하지 않아 체인이 중지된다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function RequireUserAuthentication(req, res, next) {
  if (req.user == null) {
    res.status("401").send("User is unauthenticated.");
  } else {
    next();
  }
}
 
app.get("/me/name", RequireUserAuthentication, (req, res, next) => {
  res.send(req.user.name);
});
 
app.get("/me/avatar", RequireUserAuthentication, (req, res, next) => {
  res.send(req.user.avatar);
});
cs

 

 

 

3. EX2 : 모든 경로에 대해 사용자 인증

 

  app.use(RequireUserAuthentication)를 사용하여 RequireUserAuthentication 미들웨어가 모든 경로에서 '주입'되도록 할 수 있다.

  한 가지 주의할 점은 미들웨어가 순서에 영향을 받는다는 것이다.

  따라서 아래 코드에서 app.use (RequireUserAuthentication) 이전에 정의 된 경로는 영향을받지 않는다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// This route is not affected by RequireUserAuthentication
app.get("/home", (req, res, next) => res.send(...));
 
// Require user auth for all routes defined after this line.
app.use(RequireUserAuthentication);
 
// Routes below are user sign-in required
app.get("/me/name", (req, res, next) => {
  res.send(req.user.name);
});
 
app.get("/me/avatar", (req, res, next) => {
  res.send(req.user.avatar);
});
cs

 

 

 

4. EX3 : JSON 요청 본문을 객체로 구문 분석

 

  때때로 요청 본문을 JSON 객체로 자동 변환하는 것이 유용하므로 모든 단일 경로에 대해 동일한 논리를 작성할 필요가 없다.

  

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// Converts request body into req.body as a javascript object
function JSONParser(req, res, next) {
  if (req.headers['content-type'].startsWith('application/json')) {
    const rawBody = readStreamIntoString(req);
    req.body = JSON.parse(rawBody);
  }
  next();
}
 
// Apply JSONParser middleware to all routes defined after this line
app.use(JSONParser);
 
// Reads post name and content from req.body
app.get("/new/post", (req, res, next) => {
  const postTitle = req.body.title;
  const postContent = req.body.content;
  ...
});
 
// Reads username from req.body
app.get("/new/user", (req, res, next) => {
  const userName = req.body.username;
  ...
});
cs

 

여기에서 JSON 요청 본문을 객체로 구문 분석하고 객체를 req.body로 설정하는 JSONParser 미들웨어를 만들었다.

그 객체는 경로 /new /post 및 이후에 정의된 모든 다른 경로에서 적용된다.

 

 

 

5. EX4 : Configurable한 미들웨어

 

  데이터 타입에 따라 다음과 같은 미들웨어 함수를 반환하는 '팩토리'함수를 만들어보는 것도 가능할 것이다!

  

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
function BodyParser(options) {
  if (options.type === "JSON") {
    return (req, res, next) => {
      if (req.headers["content-type"].startsWith("application/json")) {
        const rawBody = readStreamIntoString(req);
        req.body = JSON.parse(rawBody);
      }
      next();
    };
  } else if (options.type === "URL_ENCODED") {
    return (req, res, next) => {
      if (
        req.headers["content-type"].startsWith(
          "application/x-www-form-urlencoded"
        )
      ) {
        const rawBody = readStreamIntoString(req);
        req.body = new URLSearchParams(rawBody);
      }
      next();
    };
  }
}
 
app.use(BodyParser({ type: "JSON" }));
app.use(BodyParser({ type: "URL_ENCODED" }));
cs

 

 

  이처럼 미들웨어를 직접 작성하여 알맞게 사용하는 방법을 알아보았다.

  또한 익스프레스에는 많은 유용한 미들웨어 모듈이 존재한다.

  해당 미들웨어들을 잘 활용한다면 적은 코드로 생산성이 높은 서버를 만들 수 있을것이다!

+ Recent posts