ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Node.js(5) - 미들웨어와 라우팅 사용하기
    웹 개발/node.js 2023. 4. 18. 22:14

    미들웨어 간 데이터 교환하기 

     

    - 물론  req.session 객체에 데이터를 넣어도 되지만, 세션이 유지되는 동안에 데이터도 계속 유지된다는 단점이 있음

    -  우리는 요청이 끝날 때까지만 데이터를 유지하고 싶기 때문에 res.locals 객체에 데이터를 넣어 두어야 한다. 

    - 새로운 요청이 오면 res.locals는 초기화된다. 

    app.use((req, res, next) => {
      res.locals.data = '데이터 넣기';
      next();
    }, (req, res, next) => {
      console.log(res.locals.data); // 데이터 받기
      next();
    });

     

    미들웨어 안에 미들웨어 넣기 

    - 기존의 미들웨어 기능 확장에 용이하다. 

    app.use(morgan('dev'));
    // 또는
    app.use((req, res, next) => {
      morgan('dev')(req, res, next);
    });
    app.use((req, res, next) => {
      if (process.env.NODE_ENV === 'production') {
        morgan('combined')(req, res, next);
      } else {
        morgan('dev')(req, res, next);
      }
    });

     

     

    multer 

    - 이미지, 동영상 등을 비롯한 여러 가지 파일을 멀티파트 형식( enctype multipart/form-data인 폼을 통해 업로드하는 데이터의 형식)으로 업로드할 때 사용하는 미들웨어이다.

     

    multipart.html

    <form action="/upload" method="post" enctype="multipart/form-data">
        <input type="file" name="image"/>
        <input type="text" name="title"/>
        <button type="submit">업로드</button>
    </form>

     

    app.js에 추가해주기

    const multer = require('multer');
    
    const upload = multer({
      storage: multer.diskStorage({ //storage 속성 :  어디에(destination) 어떤 이름으로(filename) 저장할지를 넣기
      //  destination과 filename 함수의 req 매개변수에는 요청에 대한 정보가, file 객체에는 업로드한 파일에 대한 정보가 있음
        destination(req, file, done) {
          done(null, 'uploads/'); //done : 함수임.  첫 번째 인수에는 에러가 있다면 에러를 넣고, 두 번째 인수에는 실제 경로나 파일 이름을 넣어주면 된다. (/uploads)
       //  req나 file의 데이터를 가공해서 done으로 넘기는 형식이다.
       },
        filename(req, file, done) {
          const ext = path.extname(file.originalname); // uploads라는 폴더에 [파일명+현재시간.확장자] 파일명으로 업로드함
          done(null, path.basename(file.originalname, ext) + Date.now() + ext);
        },
      }),
      limits: { fileSize: 5 * 1024 * 1024 }, //limits 속성에는 업로드에 대한 제한 사항을 설정할 수 있으며, 파일 사이즈(fileSize, 바이트 단위)는 5MB로 제한해둠 
    });

    - 그런데 여기서 멀티 파일을 저장할 uploads 폴더가 필요하기 때문에, 직접 만들어주거나 fs모듈을 사용하여 서버가 시작할 때 생성해준다. 

     

    app.js에 추가해주기

    const fs = require('fs');
    
    try {
      fs.readdirSync('uploads');
    } catch (error) {
      console.error('uploads 폴더가 없어 uploads 폴더를 생성합니다.');
      fs.mkdirSync('uploads');
    }

     

    파일을 하나만 업로드할 수 있도록 하는 경우에는 single 미들웨어를 사용한다. 

     

    app.js에 추가하기 

    app.post('/upload', upload.single('image'), (req, res) => {
      console.log(req.file, req.body);
      res.send('ok');
    });

    - single 미들웨어를 라우터 미들웨어 앞에 넣어두면, multer 설정에 따라 파일 업로드 후 req.file 객체가 생성된다. 

    인수는 input 태그의 name이나 폼 데이터의 키와 일치하게 넣으면 된다. 

    - 업로드 성공 시 결과는 req.file 객체 안에 들어 있으며, req.body에는 파일이 아닌 데이터인 title이 들어 있게 된다. 

     

    req.file 객체 생김새 

    { 
      fieldname: 'img',
      originalname: 'nodejs.png',
      encoding: '7bit',
      mimetype: 'image/png',
      destination: 'uploads/',
      filename: 'nodejs1514197844339.png',
      path: 'uploads\nodejs1514197844339.png',
      size: 53357
    }

     

    여러 파일을 업로드하는 경우 

    multipart.html

    <form id = "form" action="/upload" method="post" enctype="multipart/form-data">
      <input type="file" name="many" multiple />
      <input type="text" name="title" />
      <button type="submit">업로드</button>
    </form>

     

    미들웨어는 single 형식 대신 array로 교체하여 사용해야 한다. 

    app.js

    app.post('/upload', upload.array('many'), (req, res) => {
      console.log(req.files, req.body);
      res.send('ok');
      });
    
    
    
    
    //싱글 형식일 때
    
    //app.post('/upload', upload.single('image'), (req, res) => {
    //  console.log(req.file, req.body);
    //  res.send('ok');
    //});

    - 업로드 결과는 req.files 배열에 들어있게 됨 

     

    파일을 여러 개 업로드하지만 input 태그나 폼 데이터의 키가 다른 경우 = fields 미들웨어 사용하기

     

    multipart.html

    <form id = "form" action="/upload" method = "post">
        <input type = "file" name = "image1"/>
        <input type = "file" name = "image2" />
        <input type = "text" name = "title" />
        <button type="submit">업로드</button>
    </form>

     

    app.js

    fields 미들웨어의 인수로 input 태그의 name을 각각 적습니다.
    
    app.post('/upload',
      upload.fields([{ name: 'image1' }, { name: 'image2' }]),
      (req, res) => {
        console.log(req.files, req.body);
        res.send('ok');
      },
    );

    -  업로드 결과는 req.files.image1, req.files.image2에 각각 들어 있게 된다.

     

     

    파일을 업로드하지 않고도 멀티파트 형식으로 업로드하는 경우

     

    multipart.html

    <form id= "form" action="/upload" method = "post" enctype = "multipart/form-data">
        <input type = "text" name = "title" />
        <button type = "submit">업로드</button>
    </form>

     

    app.js

    app.post('/upload',  upload.none(),  (req, res) => {
      console.log(req.body);
      res.send('ok');
    });

     

    - 파일을 업로드하지 않았기 때문에 req.body만 존재한다. 

     

     

    파일 업로드 관련 미들웨어 관계도

     

    Router 객체로 라우팅 분리하기

    - app.js에서 app.get 같은 메서드가 라우터 부분이고, 이 부분을 routes 폴더에 분리해서 만들어주기 

     

    routes/index.js

    const express = require('express');
    
    const router = express.Router();
    
    // GET / 라우터
    router.get('/', (req, res) => {
      res.send('Hello, Express');
    });
    
    module.exports = router;

     

    routes/user.js

    const express = require('express');
    
    const router = express.Router();
    
    // GET /user 라우터
    router.get('/', (req, res) => {
      res.send('Hello, User');
    });
    
    module.exports = router;

     

    app.js

    const express= require('express');
    const morgan = require('morgan');
    const cookieParser = require('cookie-parser');
    const session = require('express-session');
    const dotenv = require('dotenv');
    const path = require('path');
    const multer = require('multer');
    const fs = require('fs');
    const app = express();
    
    dotenv.config();
    
    
    //라우터 불러오기
    const indexFouter = require('./routes'); // index.js는 생략할 수 있기 때문에 index.js를 불러옴
    const userRouter = require('./routes/user');
    
    app.set('port', process.env.PORT || 3000);
    app.use(morgan('dev'));
    
    app.use('/', express.static(path.join(__dirname, 'public')));
    app.use(express.json());
    app.use(express.urlencoded({extended:true}));
    app.use(cookieParser(process.env.COOKIE_SECRET));
    app.use(session({
        resave : false,
        saveUninitialized:false,
        secret : process.env.COOKIE_SECRET,
        cookie:{
            httpOnly : true,
            secure : false,
        },
        name : 'session-cookie',
    }));
    
    app.use('/', indexRouter); // indexRouter는 app.use('/')에 연결,  use의 '/'와 get의 '/'가 합쳐져 GET / 라우터가 된다.
    app.use('/user', userRouter);  //  userRouter는 app.use('/user')에 연결, userRouter는 use의 '/user'와 get의 '/'가 합쳐져 GET /user 라우터가 됨
    // app.use로 연결할 때 주소가 합쳐진다. 
    
    app.use((req, res, next) => {
        res.status(404).send('Not Found');
    });
    
    app.use((err, req, res,next) => {
         console.error(err);
         res.status(500).send(err.message);
    
    }

     

    next('route')

    - 라우터에 연결된 나머지 미들웨어들을 건너띌 수 있도록 함 

     

    routes/index.js

    const express = require('express');
    
    const router = express.Router();
    
    router.get('/', (req, res, next) => {
      next('route');  //두 번째, 세 번째 미들웨어는 실행되지 않고, 주소와 일치하는 다음 라우터로 넘어가게 된다. 
    }, (req, res, next) => {
      console.log('실행되지 않습니다');
      next();
    }, (req, res, next) => {
      console.log('실행되지 않습니다');
      next();
    });
    router.get('/', (req, res) => {
      console.log('실행됩니다');
      res.send('Hello, Express');
    });
    
    module.exports = router;

    - 같은 주소의 라우터를 여러 개 만든 것(index.js에 대해서)

    - 라우터가 몇 개이든 상관없이 next를 호출하면 다음 미들웨어가 실행된다. 

     

     

     

    라우트 매개변수 

    router.get('/user/:id', (req, res) => {
      console.log(req.params, req.query);
    });

     

    : id

    - /users/1이나 /users/123 등의 요청을 처리하도록 해준다. 

    - :id에 해당하는 1이나 123을 조회할 수 있다는 점이며, req.params 객체 안에 들어 있다.

    -  :id이면 req.params.id로, :type이면 req.params.type으로 조회할 수 있음 

    - 일반 라우터 뒤에 있어야 다른 라우터를 방해하지 않는다. 

     

    router.get('/user/:id', (req, res) => {
      console.log('얘만 실행됩니다.');
    });
    router.get('/user/like', (req, res) => {
      console.log('전혀 실행되지 않습니다.');
    });

    - /user/like와 같은 라우터는 /user/:id 같은 라우트 매개변수를 쓰는 라우터보다 위에 위치해야 한다. 

     

    올바른 표현 방식

    router.get('/user/like', (req, res) => {
      console.log('이제 실행됩니다.');
    });
    router.get('/user/:id', (req, res) => {
      console.log('얘도 실행됩니다.');
    });

     

    주소에 쿼리스트링 사용하기

    - 쿼리스트링의 키-값 정보는 req.query 객체 안에 들어 있다. 

     

     

     

    주소가 같지만 메서드가 다른 코드에 대한 처리 

     

    req.params 

    { id: '123'}

    req.query

    { limit: '5', skip: '10' }

     

     

     

    routes/abc.js

    router.route('/abc')
      .get((req, res) => {
        res.send('GET /abc');
      })
      .post((req, res) => {
        res.send('POST /abc');
      });

     

    req 객체 메서드 및 속성

     

     

    res 객체의 속성 및 메서드

     

    메서드 체이닝 

    - res, req 객체의 메서드를 연달아 이어붙여 코드양을 줄이도록 함 

    res
      .status(201)
      .cookie('test', 'test')
      .redirect('/admin');

    '웹 개발 > node.js' 카테고리의 다른 글

    Node.js(7) - 데이터베이스, 시퀄라이즈, 몽구스  (0) 2023.04.22
    Node.js(6) - 템플릿 엔진  (0) 2023.04.21
    node.js(4) - Express.js 시작하기  (0) 2023.04.15
    Node.js(3)  (0) 2023.04.14
    Node.js(2)  (0) 2023.04.12
Designed by Tistory.