Node.js 6장 Express 웹 서버 구현 [개정 3판] Node.js 교과서 - 기본부터 프로젝트 실습까지

남경민·2023년 4월 7일

Node.js

목록 보기
1/3
  • 6.1 시작

    • npm init → package.json 생성

      //package.json
      {
        "name": "learn-express",
        "version": "0.0.1",
        "description": "익스프레스를 배우자",
        "main": "app.js",
        "scripts": {
          "start": "nodemon app" //추가해주기! (app.js를 nodemon으로 실행, 서버 코드에 수정 사항 생길 때마다 서버 자동 재시작)
        },
        "author": "ZeroCho",
        "license": "MIT"
      }
    • express 시작

      $ npm i express
      $ npm i -D nodemon
    • 서버 역할 app.js
      - GET 요청 외에도 POST, PUT, PATCH, DELETE, OPTIONS에 대한 라우터를 위한 app.post, app.put, app.patch. app.delete, app.options 메서드가 존재

      //app.js
      const express=require('express');
      
      const app=express();
      app.set('port',process.env.PORT ||3000); //서버 실행될 포트 설정
      //process.env.PORT에 속성값이 있다면 사용하고, 없다면 기본값 3000번 포트 이용
      
      app.get('/',(req,res)=>{ //주소에 대한 GET 요청이 올때 어떤 동작하는지, req: 요청에 관한 정보 객체, res: 응답에 관한 정보 객체
          res.send('Hello, Express');  //현재 GET / 요청 시 응답으로 Hello, Express 전송
      });
      
      app.listen(app.get('port'),()=>{ //서버 시작!!! 꼭 해야함~~ 중요!
          console.log(app.get('port'),'번 포트에서 대기 중');
      });
    • 서버 실행 : npm start

  • 6.2 자주 사용하는 미들웨어

    • app.use

      //app.js
      const express=require('express');
      
      const app=express();
      app.set('port',process.env.PORT ||3000); //서버 실행될 포트 설정
      //process.env.PORT에 속성값이 있다면 사용하고, 없다면 기본값 3000번 포트 이용
      
      app.use((req,res,next)=>{ //app.use : 미들웨어 역할, 매개변수 : req,res,next
          //next : 다음 미들웨어로 넘어가는 함수, next를 실행하지 않으면 다음 미들웨어 실행X 
          console.log('모든 요청에 다 실행됨');
          next();
      });
      
      app.get('/',(req,res,next)=>{ //주소에 대한 GET 요청이 올때 어떤 동작하는지, req: 요청에 관한 정보 객체, res: 응답에 관한 정보 객체
          res.send('Hello, Express');  //현재 GET / 요청 시 응답으로 Hello, Express 전송
          next();
      },(req,res)=>{ //아래 미들웨어로 전달
          throw new Error('에러는 에러 처리 미들웨어로 갑니다!');
      });
      
      app.use((err,req,res,next)=>{ //에러 처리 미들웨어 매개변수 : err,req,res,next ,모든 매개변수 사용안해도 꼭 4개여야함
          console.error(err);
          res.status(500).send(err.message); //기본값 : 200, 특별한 경우 아니면 에러 처리 미들웨어는 가장 아래 위치
      });
      
      app.listen(app.get('port'),()=>{ //서버 시작!!! 꼭 해야함~~ 중요!
          console.log(app.get('port'),'번 포트에서 대기 중');
      });
    • 실무 사용 패키지

      $ npm i morgan cookie-parser express-session dotenv
      • body-parser 패키지 설치

        $ npm i body-parser
        //app.js
        const express=require('express');
        const morgan=require('morgan'); //요청과 응답에 대한 정보 콘솔에 기록
        const cookieParser=require('cookie-parser');
        const session=require('express-session');
        const dotenv=require('dotenv'); //process.env 관리, .env파일 읽어서 process.env로 만든다
        const path=require('path'); 
        const bodyParser = require('body-parser');
        
        dotenv.config();
        const app=express();
        app.set('port',process.env.PORT || 3000);
        
        app.use(morgan('dev')); //개발 환경 : dev, 배포 환경 : combined
        
        app.use('/',express.static(path.join(__dirname,'public'))); //static : 정적인 파일 제공하는 라우터 역할, app.use('요청 경로', express.static('실제 경로'));
        //서버의 폴더 경로와 요청 경로가 다른 문제를 해결함
        
        //body-parser: 요청의 본문에 있는 데이터를 해석해서 req.body 객체로 만들어주는 미들웨어, 보통 폼 데이터나 AJAX 요청의 데이터 처리
        //멀티파트(이미지,동영상,파일)데이터 처리 못함, express에서 일부 제공, 버퍼나 텍스트 요청처리하려면 따로 설치 필요
        //body-parser 는 내부적으로 스트림 처리해 req.body에 추가된다!!
        app.use(express.json()); //json 형식
        app.use(express.urlencoded({extended:false})); //URL-encoded형식(폼 전송), extended: false 면 노드의 querystring모듈을 사용해 쿼리스트링 해석, ture면 qs모듈 사용해 쿼리 스트링 해석
        app.use(bodyParser.raw());
        app.use(bodyParser.text());
        
        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((req,res,next)=>{
            console.log('모든 요청에 다 실행됩니다.');
            next();
        });
        //.env
        COOKIE_SECRETo=cookiesecret
    • 6.2.6 미들웨어 특성 활용

      • 미들웨어는 req, res, next를 매개변수로 갖는 함수(에러 처리 미들웨어만 예외적으로 err, req, res, next를 가집니다)로서 app.use나 app.get, app.post 등으로 장착합니다. 특정한 주소의 요청에만 미들웨어가 실행되게 하려면 첫 번째 인수로 주소를 넣으면 됩니다.

      • 미들웨어 장착 순서에 따라 어떤 미들웨어는 실행되지 않을수도 있음

      • app.set : 익스프레스에서 전역적으로 사용, 하나의 요청 안에서만 유지되어야 하는 값을 넣기에는 부적절

        → res.local 객체 사용, 하나의 요청 안에서만 유지

      • 미들웨어 안에 미들웨어 넣는 방법 : 기존 미들웨어 기능 확장, 조건문에 따라 다른 미들웨어 처리
        - ex) 분기 처리

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

      • 이미지, 동영상 등 여러 가지 파일을 멀티파트 형식으로 업로드할 때 사용
  • 6.3 Router 객체로 라우팅 분리

    //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'); //process.env 관리, .env파일 읽어서 process.env로 만든다
    const path=require('path'); 
    const bodyParser = require('body-parser');
    
    dotenv.config();
    const indexRouter = require('./routes/index');
    const userRouter = require('./routes/user');
     
    const app=express();
    app.set('port',process.env.PORT || 3000);
      
    //app.js에 연결할 때 주소가 합쳐짐
    app.use('/', indexRouter);
    app.use('/user', userRouter);
    
    app.use((req, res, next) => {
      res.status(404).send('Not Found');
    });
    
    app.listen(3000,()=>{  //서버 시작!!! 꼭 해야함~~ 중요!
        console.log("서버 시작!")
    })
    • 그 외의 라우터 기능
      • next(’route’), next() : 라우터에 연결된 나머지 미들웨어들 건너뛰고 싶을 때 사용

        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');
        });
      • 라우터 주소에 정규표현식을 비롯한 특수한 패턴 사용가능!

        → 라우트 매개변수 패턴

        router.get('/user/:id', (req, res) => {
          console.log('얘만 실행됩니다.');
        });
        router.get('/user/like', (req, res) => {
          console.log('전혀 실행되지 않습니다.');
        });
      • /users/1 이나 /users/123 등의 요청도 이 라우터가 처리

      • :id에 해당하는 1이나 123을 조회 가능, req,params 객체안에 들어있음

      • :id면 req.params.id로 , :type 이면 req.params.type으로 조회 가능!

      • 주의 할점: 일반 라우터보다 뒤에 꼭 위치해야함!!!

      • 주소에 쿼리스트링도 가능 : 쿼리스트링의 키-값 정보는 req.query 객체 안에 들어있음

        ex) /users/123?limit=5&skip=10 주소 요청

        → req.params와 req.query : { id: '123' } { limit: '5', skip: '10' }

      • app.js에서 에러 처리 미들웨어 위에 넣어둔 미들웨는 일치하는 라우터 없을 때 404 상태 코드 응답 역할 → 익스프레스가 자체적으로 404에러 처리해주기는 하지만, 웬만하면 404응답 미들웨어와 에러 처리 미들웨어를 연결하는게 좋음!!

        app.use((req, res, next) => {
          res.status(404).send('Not Found');
        });
      • 주소는 같지만 메서드는 다른 코드가 있을 때, 하나의 덩어리로 묶음

        router.route('/abc')
          .get((req, res) => {
            res.send('GET /abc');
          })
          .post((req, res) => {
            res.send('POST /abc');
          });
  • 6.4 req,res 객체 살펴보기

    • req 객체

      • req.app: req 객체를 통해 app 객체에 접근할 수 있습니다. req.app.get('port')와 같은 식으로 사용할 수 있습니다.
      • req.body: body-parser 미들웨어가 만드는 요청의 본문을 해석한 객체입니다.
      • req.cookies: cookie-parser 미들웨어가 만드는 요청의 쿠키를 해석한 객체입니다.
      • req.ip: 요청의 ip 주소가 담겨 있습니다.
      • req.params: 라우트 매개변수에 대한 정보가 담긴 객체입니다.
      • req.query: 쿼리스트링에 대한 정보가 담긴 객체입니다.
      • req.signedCookies: 서명된 쿠키들은 req.cookies 대신 여기에 담겨 있습니다.
      • req.get(헤더 이름): 헤더의 값을 가져오고 싶을 때 사용하는 메서드입니다.
    • res 객체

      • res.app: req.app처럼 res 객체를 통해 app 객체에 접근할 수 있습니다.
      • res.cookie(키, 값, 옵션): 쿠키를 설정하는 메서드입니다.
      • res.clearCookie(키, 값, 옵션): 쿠키를 제거하는 메서드입니다.
      • res.end(): 데이터 없이 응답을 보냅니다.
      • res.json(JSON): JSON 형식의 응답을 보냅니다.
      • res.locals: 하나의 요청 안에서 미들웨어 간에 데이터를 전달하고 싶을 때 사용하는 객체입니다.
      • res.redirect(주소): 리다이렉트할 주소와 함께 응답을 보냅니다.
      • res.render(뷰, 데이터): 다음 절에서 다룰 템플릿 엔진을 렌더링해서 응답할 때 사용하는 메서드입니다.
      • res.send(데이터): 데이터와 함께 응답을 보냅니다. 데이터는 문자열일 수도, HTML일 수도, 버퍼일 수도, 객체나 배열일 수도 있습니다.
      • res.sendFile(경로): 경로에 위치한 파일을 응답합니다.
      • res.set(헤더, 값): 응답의 헤더를 설정합니다.
      • res.status(코드): 응답 시의 HTTP 상태 코드를 지정합니다.
    • 메서드 체이닝

      res
        .status(201)
        .cookie('test', 'test')
        .redirect('/admin');
profile
백엔드 개발을 좋아하고 공부하고 있습니다. 코드 작성 뿐만 아니라 쿼리 성능 고려, 클린 코드, 테스트 케이스 작성에 주력해 모든 에러 상황을 대비하는 개발자로 성장하고 싶습니다.

0개의 댓글