ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Express] app.use()에 대해
    개발/node.js 2020. 3. 28. 18:44

    미들웨어 레벨

    app.use() 함수에 대해 알아보기 전에 미들웨어 동작 레벨에 대해 알아 보겠다.

    1. 애플리케이션 레벨

    2. 라우터 레벨

    일단은 두가지로 나누어질 수 있다.

    물론 단계는 애플리케이션 -> 라우터 단계로 실행순서가 이루어져 있다고 볼 수 있다.

     

    애플리케이션 레벨과 라우터 레벨은 실행단계의 차이지 기능적으론 다른 점이 없다.

    애플리케이션 분기 + 라우터 분기 로 더 세세하게 요청 URL을 분리하여 제어가 가능하다는 점이다.

    코드로 알아보자.

    var indexRouter = require('./routes/index');
    var usersRouter = require('./routes/users');
    
    var app = express();
    
    app.use('/', indexRouter);
    app.use('/users', usersRouter);

    위의 예는 애플리케이션 단계에서 '/' 와 '/users'로 URL을 분리하여 처리를 하도록 한것이다.

    또한 callback 인자에 express.Router() 오브젝트를 생성하여 넣음으로 라우터 단계에서의 URL 제어도 가능 하도록 등록하였다.

    var express = require('express');
    var router = express.Router();
    
    /* GET users listing. */
    router.get('/', function(req, res, next) {
      console.log('originalUrl : '+req.originalUrl);
      console.log('baseUrl : '+req.baseUrl);
      console.log('path : '+req.path);
      res.send('respond with a resource');
    });
    
    router.get('/user', function(req, res, next) {
      console.log('originalUrl : '+req.originalUrl);
      console.log('baseUrl : '+req.baseUrl);
      console.log('path : '+req.path);
      res.send('respond with a resource');
    });
    
    module.exports = router;
    

     위의 예는 라우터 단계의 미들웨어다.

    app.use() 처럼 router.use()도 쓸 수 있고 app.METHOD() 처럼 router.METHOD()도 사용 가능하다.

    use와 METHOD의 다른점은 use()는 모든 METHOD에서 동작한다는 것이고 METHOD()는 지정된 요청(GET, POST, PUT, DELETE 등)에서만 동작을 한다는 것

     

    위는 express에서 라우터 기능이 어떻게 흘러가는가를 보여주고 있다.

    1. 애플리케이션 단계에서의 URL 제어

    - '/', 'users' 두가지 분기

    2. 라우터 단계에서의 URL 제어 (예는 'users' 미들웨어)

    - '/', 'user' 두가지 분기

     

    위에서 언급한 미들웨어의 라우터 실행 단계는 app.use()의 동작과도 밀접한 관련이 있어서 미리 소개를 하였다.

    자 그럼 본격적으로 app.use()에 대해 알아보자.

    URL은 '/users/user'로 진행하겠다.

    app.use(cookieParser());
    app.use('/users', usersRouter);
    .
    .
    .
    
    router.get('/', function(req, res, next) {
      console.log('originalUrl : '+req.originalUrl);
      console.log('baseUrl : '+req.baseUrl);
      console.log('path : '+req.path);
      res.send('respond with a resource');
    });
    
    router.get('/user', function(req, res, next) {
      console.log('originalUrl : '+req.originalUrl);
      console.log('baseUrl : '+req.baseUrl);
      console.log('path : '+req.path);
      res.send('respond with a resource');
    });

    모든 요청에 cookieParser()을 실행, '/users'라는 URL이 들어오면 usersRouter을 실행

    // cookieParser 로그
    p originalUrl : /users/user
    p baseUrl : 
    p path : /users/user
    
    // usersRouter 로그
    originalUrl : /users/user
    baseUrl : /users
    path : /user

    'http://localhost:3000/users/user'을 웹브라우저에 쳤을 때 url의 변화를 로그로 찍어보았다.

    여기서 중요한 request 오브젝트가 가지고 있는 멤버변수에 대해 알아보자.

    1. originalUrl

    - 이 변수는 express 에서 동작하는 http module의 request.url라는 변수를 라우팅을 목적으로 재생성한 변수이다. (cookieParser 가 request.headers.cookie 를 request.cookies로 가공을 거쳐 재생성한 것처럼) 실제 클라이언트가 브라우저에 입력한 url을 뜻한다.

    2. baseUrl

    - 이 변수는 간단히 말하자면 애플리케이션 레벨에 등록된 URL을 뜻한다. 실제로 app.use() 함수에 path 값을 넣지 않던가 '/'를 통해 모든 요청에 해당하는 미들웨어를 등록하면 위의 cookieParser 로그처럼 값이 비어있다.

    3. path
    - baseUrl이 애플리케이션 레벨의 URL이라면, 이 변수는 라우터 레벨에 등록된 URL 이다.

     

    실행 순서를 같이 보자면

    위와 같은 프로세스로 라우팅을 하는 것 같다.

    결국 app.use()의 매개변수인 path는 originalUrl과 match하는 애플리케이션 미들웨어를 동작키는 것이고, 그 이후 express.Router()로 등록된 미들웨어일 경우 baseUrl을 제외한 나머지 path로 라우터 미들웨어를 동작시키는 것 같다.

    여기서 express.Router()로 등록된 애플리케이션 미들웨어의 path가 root path('/') 일 경우에는 라우터 레벨 단계까지의 path와 일치하여야 실행 되는 것 같다.

    물론 매개변수 path는 정규식 표현으로도 실행이 가능하다.

     

    직접 미들웨어를 간단하게 등록하여 아래와 같이 실행 가능하다.

    app.use('/users',cookieParser());
    
    app.use('/', (req, res, next)=>{
      console.log('모든 요청에 log 남기기');
      next();
    });
    
    app.use('/', indexRouter);
    app.use('/users', usersRouter);

    http://localhost:3000/users/user 요청 시 log 

    cookieParser log
    모든 요청에 log 남기기
    usersRouter '/users/user' log

     

    또한 중복으로 callback 함수를 등록 가능

    app.use('/', (req, res, next)=>{
      console.log('모든 요청에 log 1');
      next();
    }, (req, res, next)=>{
      console.log('모든 요청에 log 2');
      next();
    });
    app.use('/', indexRouter);
    app.use('/users', usersRouter);

    http://localhost:3000/users/user 요청 시 log 

    모든 요청에 log 1
    모든 요청에 log 2
    usersRouter '/users/user'

     

    중복으로 등록된 callback 함수 사이에도 등록된 순서대로 실행되게 되어있다.

    연속으로 등록된 callback 메소드의 순서를 제어하기위해, 다음 미들웨어를 호출하고 싶다면 next('route') 를 실행시키면 된다. 이때 path는 동일하여야 하고 app.METHOD()나, router.METHOD()를 사용해야지만 가능하다.

    이것이 뜻하는 것은 path가 같은 METHOD로 스택(자료구조?)이 생성되어 순차적으로 실행하기 때문인 것 같다.

    아래는 예시이다.

    app.use('/', (req, res, next)=>{
      console.log('모든 요청에 log 1');
      next('route');
    }, (req, res, next)=>{
      console.log('모든 요청에 log 2');
      next();
    });
    app.use('/', indexRouter); // console.log('indexRouter '/'');

    app.use로 아무리 path가 '/'로 같다고는 하나 특정된 METHOD가 아니기 때문에 next('route')가 제대로 동작하지 않는다.

    모든 요청에 log 1
    모든 요청에 log 2
    indexRouter '/'

    아마 app.use()에서는 next('route')의 'route' 매개변수를 무시하고 그냥 next()로 동작을 하는 것 같다.

    그러나 다음과 같이 app.METHOD()로 get을 특정해버린다면?

    app.get('/', (req, res, next)=>{
      console.log('모든 요청에 log 1');
      next('route');
    }, (req, res, next)=>{
      console.log('모든 요청에 log 2');
      next();
    });
    app.get('/', indexRouter);
    모든 요청에 log 1
    indexRouter '/'

    원하는 순서대로 라우터 미들웨어가 동작했다. 아마 아래와 같이 생성되어 있을 것이다.

     

    이렇게 오늘은 use(), METHOD() 에 대해서 알아보았다. 다음번엔 이것을 바탕으로 express --ejs 프로젝트의 구조를 알아보자.

    댓글

Designed by Tistory.