경일게임아카데미 멀티 디바이스 메타버스 플랫폼 개발자 양성과정 20220919 ~ 0920 개인 공부 - 보충 2022/04/04~2022/12/14

Jinho Lee·2022년 9월 21일
0

2022.09.19 ~ 20 개인 보충학습 - 22.09.16 경일 메타버스 24주차 4일 수업내용. Node.js - npm 패키지 매니저, 익스프레스

패키지 매니저

  • 자료 : 교과서 “Node.js 교과서” ch. 5 패키지 매니저 p. 207

npm

  • p. 208 ~ 209

  • Node Package Manager의 약어

  • 특정 기능의 패키지를 찾아 설치 가능

    • 패키지 : npm에 업로드된 노드 모듈
  • 패키지가 다른 패키지를 사용 → 의존 관계

package.json으로 패키지 관리

  • p. 209 ~ 218

  • package.json : 설치한 패키지의 버전을 관리하는 파일

    • 패키지 하나가 다른 여러 패키지에 의존
      → 복잡하게 얽히는 의존 관계
      → 그래서 이를 모두 관리하는 package.json이 필요

    • package-lock.json : 패키지들의 정확한 버전의존 관계 저장

      • 패키지를 설치 / 수정 / 삭제할 때마다 패키지 간 내부 의존 관계를 저장
  • 명령어를 등록해두고 사용 가능

    • ex. start 명령어에 node [파일명]을 저장하고 npm start로 실행

      • starttest 같은 스크립트는 run을 붙이지 않아도 실행 가능

패키지 설치

  • 명령어

    • npm install [패키지 이름] : 패키지를 설치하는 명령어
  • 개발용 패키지 설치

    • 실제 배포에는 사용되지 않고 개발 중에만 사용되는 패키지

    • 명령어

      • npm install —save-dev [패키지] […]

        • —save-dev키워드가 개발용 패키지임을 가리킨다.
  • 전역 (Global) 설치

    • 패키지를 npm이 설치되어 있는 폴더에 설치

      • 위의 경로는 보통 시스템 환경 변수 ⇒ 콘솔의 명령어로 사용 가능
    • 명령어로 사용하기 위해 행한다.

    • 명령어

      • npm install —global [패키지] […]

      • —global 키워드가 전역 설치임을 가리킨다.

    • 전역 설치를 하지 않고 명령어로 사용

      • 전역 설치한 패키지는 package.json에 기록되지 않아 다시 설치하기 어려움

      • 명령어 npx

        • 패키지를 개발용으로 설치 후 npx를 붙여 실행
          → 명령어로 사용 가능, 버전 관리 용이
  • 명령어 줄여쓰기

    • npm installnpm i

    • —save-dev-D

    • —global-g

패키지 버전

  • p. 218 ~ 220

  • SemVer 방식

    • 노드 패키지 버전 방식

    • Semantic Versioning (유의적 버전)의 약어

      • 버전을 구성하는 세 자리 모두 의미를 갖고 있다.
    • 패키지 간 복잡한 의존 관계에 따른, 버전 업그레이드로 인한 에러를 방지하기 위함

    • 자릿수

      1. major 버전

        • 하위 호환이 안 될 정도로 패키지의 내용이 수정됨

        • 업데이트를 했을 때 문제가 발생할 확률이 높다.

        • 0 → 초기 개발 중, 1 이상 → 정식 버전

      2. minor 버전

        • 하위 호환이 되는 기능 업데이트

        • 업데이트를 했을 때 문제가 없어야 한다.

      3. patch 버전

        • 기존 기능에 문제가 있어 수정

        • 업데이트를 했을 때 문제가 없어야 한다.

    • 수정 사항이 생기면 자릿수의 의미에 맞게 올려 새로운 버전을 배포
      → 기존 버전은 절대 수정하지 않는다.

    • 장점

      1. 배포된 버전 내용이 변하지 않아 패키지 간 의존 관계에 큰 도움

        • 특정 버전이 정상적으로 동작하면 같은 버전을 사용할 때 어떠한 경우라도 정상적으로 동작하리라 신뢰 가능
      2. 패키지 버전만 보고도 에러 발생 여부 가늠이 가능

        • major → 주의

        • 그 외 → 신뢰 가능

    • package.json의 경우, 추가 문자로 설치 / 업데이트 정보를 제공해준다.

      • ^ : minor 버전까지만 설치 / 업데이트 가능

        • ex. npm express@^1.1.1

        • 다른 표현 - 1.x.x

      • ~ : patch 버전까지만 설치 / 업데이트 가능

        • ex. npm express@~1.1.1

        • 다른 표현 - 1.1.x

      • > / < / > = / < = / = : 초과 / 미만 / 이상 / 이하 / 동일 버전의 설치 / 업데이트 가능

        • ex. npm express@>1.1.1
      • @latest : 안정된 최신 버전 패키지 설치 / 업데이트 가능

        • 다른 표현 - @x

        • ex. npm express@latest / npm express@x

      • @next : 안정되지 않은 알파 / 베타 버전의 패키지 설치 / 업데이트 가능

        • 다른 표현 키워드

          • -alpha.0 : 알파 버전

          • -beta.1 : 베타 버전

          • -rc.0 : 출시 직전 (Release Candidate)

익스프레스 웹 서버

  • 자료 : 교과서 “Node.js 교과서” ch. 6 익스프레스 웹 서버 만들기 p. 227

  • 익스프레스 : 웹 서버 제작에서 코드의 가시성과 확장성을 높이기 위한 웹 서버 프레임워크

익스프레스 프로젝트 시작

  • p. 229 ~ 232

  • package.json

{
  "name": "learn-express",
    "version": "0.0.1",
      "scripts": {
        "start": "nodemon app"
      },
        "devDependencies": {
          "nodemon": "^2.0.20"
        },
          "dependencies": {
            "cookie-parser": "^1.4.5",
              "express": "^4.18.1",
                "express-session": "^1.17.1",
                  "morgan": "^1.10.0"
          }
}
  • 설명

    • scripts

      • start 속성을 반드시 넣는다.

      • nodemon app : app.js을 nodemon으로 실행한다.

      • nodemon : 서버 코드에 수정 사항이 생길 때마다 서버를 자동으로 재시작해주는 모듈

        • 콘솔에 rs를 입력해 수동으로 재시작 가능

        • npm i -D nodemon 코드로 개발용으로 설치했기에, 디버그 시에만 적용된다.

  • app.js

const express = require('express');
const path = require('path');

const app = express();
app.set('port', process.env.PORT || 3000);

app.get('/', (req, res) => {
  // res.send('Hello, Express');
  res.sendFile(path.join(__dirname, '/6_1_index.html'));
});

app.listen(app.get('port'), () => {
  console.log(app.get('port'), '번 포트에서 대기 중');
});
  • Express 모듈을 실행해 app 변수에 할당

  • Express의 내부에 http 모듈이 내장되어 있어 서버 역할 가능

  • app.set(키, 값) : 데이터를 저장 / app.get(키) : 데이터를 가져옴

    • app.set('port', process.env.PORT || 3000);

      • 서버가 실행될 포트를 설정

      • process.env 객체에 PORT 속성이 있다면 그 값 사용 || 없다면 3000 사용

    • app.get(주소, 라우터) : 주소에 대한 GET 요청이 올 때 어떤 동작을 할지 지정

      • 주소 : ‘/’

      • 라우터 : 경로를 선택하는 함수

        • Express에서는 res.send() 메소드 사용해 문자열 전송

        • res.sendFile() 메소드 사용해 파일(이 경우 HTML) 전송

    • GET 요청 외에도 POST / PUT / PATCH / DELETE / OPTIONS 요청에 대한 라우터를 위한 메소드

      • app.post / app.put / app.patch / app.delete / app.opptions
  • listen : 포트를 연결하고 서버를 실행

    • 포트는 app.get(’port’)로 가져옴

미들웨어

  • p. 232 ~ 250

  • 요청과 응답의 중간에 위치해 미들웨어

    • 요청과 응답을 조작해 기능을 추가 / 나쁜 요청 필터링 (예외 처리)
  • app.use(미들웨어) 형식으로 사용

    • app.use(미들웨어) : 모든 요청에서 미들웨어 실행

    • app.use(’/abc’, 미들웨어) : /abc로 시작하는 요청에서 미들웨어 실행

    • app.post(’/abc’, 미들웨어) : /abc로 시작하는 POST 요청에서 미들웨어 실행

  • 미들웨어는 위에서 아래로 순서대로 실행

  • next() : 다음 미들웨어로 넘어가는 함수

  • 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');

dotenv.config();
const app = express();
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: false }));
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',
}));

const multer = require('multer');
const fs = require('fs');

try {
  fs.readdirSync('uploads');
} catch (error) {
  console.error('uploads 폴더가 없어 uploads 폴더를 생성합니다.');
  fs.mkdirSync('uploads');
}
const upload = multer({
  storage: multer.diskStorage({
    destination(req, file, done) {
      done(null, 'uploads/');
    },
    filename(req, file, done) {
      const ext = path.extname(file.originalname);
      done(null, path.basename(file.originalname, ext) + Date.now() + ext);
    },
  }),
  limits: { fileSize: 5 * 1024 * 1024 },
});
app.get('/upload', (req, res) => {
  res.sendFile(path.join(__dirname, 'multipart.html'));
});
app.post('/upload', upload.single('image'), (req, res) => {
  console.log(req.file);
  res.send('ok');
});

app.get('/', (req, res, next) => {
  console.log('GET / 요청에서만 실행됩니다.');
  next();
}, (req, res) => {
  throw new Error('에러는 에러 처리 미들웨어로 갑니다.')
});
app.use((err, req, res, next) => {
  console.error(err);
  res.status(500).send(err.message);
});

app.listen(app.get('port'), () => {
  console.log(app.get('port'), '번 포트에서 대기 중');
});
  • .env 파일 생성 → 코드 COOKIE_SECRET=cookiesecret

    • dotenv 패키지로 .env 파일을 읽어 process.env 객체 생성

    • 보안과 설정의 편의성을 위함

  • 위 코드에 사용된 미들웨어 분석

    • req, res, next가 없고 next() 호출이 없는 미들웨어들은 내부적으로 포함하고 있기 때문 → 기본 제공

에러 처리 미들웨어

  • 매개변수는 err, req, res, next로 네 개

    • 사용하지 않더라도 반드시 네 개

    • err : 에러에 관한 정보

  • 특별한 경우가 아니라면 가장 아래에 위치

  • 뒤에서 더 자세히 소개 (ch. 6.5.3, 템플릿 엔진-에러 처리 미들웨어)

morgan

  • 요청과 응답에 대한 정보를 콘솔에 기록

  • app.use(morgan('dev'));

  • 인수 : dev, combined, common, short, tiny

static

  • 정적인 파일들을 제공하는 라우터 역할

  • app.use('요청 경로', express.static('실제 경로');

  • 함수의 인수로 정적 파일들이 담겨 있는 폴더 지정

  • 서버의 폴더 경로와 요청 경로가 다르므로 외부에서 서버의 구조 파악이 어려움
    ⇒ 보안상 이득

  • 파일을 읽을 필요 없이 제공

  • 파일이 없다면 next() 호출, 있다면 호출 X

body-parser

  • 요청의 본문에 있는 데이터를 해석하여 req.body 객체로 만들어주는 미들웨어

  • 보통 폼 데이터나 AJAX 요청 데이터 처리

  • 멀티파트 (이미지, 동영상, 파일) 데이터는 처리 불가

  • 예시

    • app.use(express.json());

    • app.use(express.urlencoded({ extended: false }));

  • 요청에 동봉된 쿠키를 해석해 req.cookie 객체로 만드는 미들웨어

  • app.use(cookieParser(비밀키));

  • 쿠키를 생성할 때 쓰이는 것은 아니다.

  • signed 옵션 : true로 설정하면 서명이 붙는다.

express-session

  • 세션 관리용 미들웨어

  • 세션을 구현하거나 특정 사용자를 위한 데이터를 임시 저장할 때 유용

  • 인수로 세션에 대한 설정을 받는다.

    • resave : 요청이 올 때 세션에 수정 사항이 생기지 않더라도 세션을 다시 저장할지 여부

    • saveUninitialized : 세션에 저장할 내역이 없더라도 처음부터 세션을 생성할지 여부

  • 세션 관리 시 클라이언트에 쿠키를 보낸다 - 세션 쿠키

    • secret : 안전하게 쿠키를 전송하기 위한 서명
  • cookie 옵션 : 세션 쿠키에 대한 설정

  • store 옵션 : 데이터베이스 연결

미들웨어의 특성

  • 첫 번째 인수로 주소 ⇒ 특정한 주소의 요청에만 미들웨어 실행

  • 하나의 app.use() 메소드에 복수의 미들웨어 장착 가능

    • 미들웨어의 장착 순서에 따라 어떤 미들웨어는 실행되지 않을 수도 있다.
  • next() 함수에 인수를 넣어 특수한 동작

    • ‘route' : 다음 라우터의 미들웨어로 이동

    • 그 외의 인수 : 에러 처리 미들웨어로 이동 → 인수는 err 매개변수로 넘어감

  • 미들웨어 간에 데이터를 전달하는 방법

    • 세션을 사용할 때, req.session 객체에 데이터 저장

      • 세션이 유지되는 동안 데이터 유지
    • req 객체에 데이터 저장

      • 요청이 끝날 때까지만 데이터를 유지

      • 요청이 처리되는 동안 req.data를 통해 미들웨어 간에 데이터 공유 가능

        • 새로운 요청이 오면 req.data 초기화

        • 속성명 .data는 임의 - 다른 미들웨어와 겹치지 않는다면 무엇이든 무방

    • app.set

      • 익스프레스에서 데이터 저장

      • 익스프레스 전역적으로 사용
        → 앱 전체 설정 공유에 적절, 사용자 개개인의 값 저장에는 부적절

  • 미들웨어 패턴

    • 미들웨어 안에 미들웨어 삽입

      • 예시

           app.use(morgan('dev'));
           // 위와 아래는 같은 기능
           app.use((req, res, next) => {
             morgan('dev')(req, res, next);
           });
    • 이 패턴이 유용한 이유 : 미들웨어 기능의 확장

      • ex. 분기 처리 등

      • 예시 코드

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

multer

  • 이미지, 동영상 등 여러 가지 파일들을 멀티파트 형식으로 업로드할 때 사용하는 미들웨어

    • 멀티파트 형식 : enctypemultipart/form-data인 폼을 통해 업로드하는 데이터의 형식

    • 멀티파트 HTML 예시 : multipart.html

      <form id="form" action="/upload" method="post" enctype="multipart/form-data">
        <input type="file" name="image1" />
        <input type="file" name="image2" />
        <input type="text" name="title" />
        <button type="submit">업로드</button>
      </form>
  • 프로젝트 시작으로 시간 부족 : 후에 내용 전부 정리 예정

Router 객체로 라우팅 분리

  • p. 251 ~ 255

req, res 객체

  • p. 255 ~ 256

템플릿 엔진

  • p. 257 ~ 275

  • 프론트엔드에 필요한 기술. 필요하면 다시 체크

에러 처리 미들웨어

0개의 댓글