카테고리 없음

2022 12 25 WIL

msdou45 2022. 12. 26. 07:31

우리밋_woorimIT Node.js 맛보기

 

 

로그인 & 회원가입 기능을 고퀄리티로 구축해보자.

사이트 : https://www.youtube.com/@_woorimit1343/featured

 

 

폴더 : kimminsoo -> woorimit -> node_base 

 

 

 

_________________________________________________________________________________________________________

 

 

 

 

 

 

__________________________________________________

 

1-1  로그인 & 회원가입 서비스 구축 오리엔테이션

 

 

 

우리가 이번 코스를 통해서 배우게 될 것들.

 

익스프레스

모듈화. MVC 패턴. 모델, 컨트롤러, 뷰.

package.json 컨트롤 및 조작

클라이언트의 요청 로그를 콘솔에 출력. 모듈 사용할거야.

DB 연동하기. Mysql 을 aws - RDS 로 사용.

GUI - 워크밴치 사용

TDD 개념 활용해보기.

 

넓게, 얕게!

 

 

 

 

 

__________________________________________________

 

1-2  개발환경 세팅

 

 

 

1.

Visual Studio Code 에디터 사용

 

2.

node.js LTS 버전 사용

 

3.

npm 사용

 

 

 

 

 

 

 

__________________________________________________

 

1-3  express 로 서버 띄워보기

 

 

 

폴더 : kimminsoo -> woorimit -> node_base -> login-lecture

 

 

 

1.

app.js 만들기.

=> 참고.

터미널에 < pwd > 라고 입력하면 현재 디렉토리의 절대주소가 나와.

 

Npm init

Npm I express

 

 

 

 

 

 

 

__________________________________________________

 

1-4  http 로 서버 띄워보기

 

 

폴더 : kimminsoo -> woorimit -> node_base -> login-lecture

 

 

— express 를 사용하지 않고 서버를 구축해보자.

=> http 를 사용해서 맛보기만. 알고는 있어야 하잖아?

 

 

**

전체 주석처리

=> 블록 씌운 후 cmd + /

 

 

——

const http = require("http");    // 내장 모듈

const app = http.createServer((req, res) => {

    res.writeHead(200, { "Content-Type": "text/html; charset=utf-8"});     

            // 내가 보낸 게 text 중에 html 이고 charset 은 utf-8 이니 이대로 해석해달라, 라고 브라우저에 전달.

    console.log(req.url);       // 루트 경로 이하에 있는 경로들을 우리가 파싱해 올 수 있다.

    if (req.url === "/") {

        res.end("여기는 루트 url 입니다.");      // http 에서는 send 라는 메소드가 없어.

    } else if (req.url === "/login") {

        res.end('여기는 로그인 화면입니다.');

    }

});

 

app.listen(3001, () => {

    console.log("http로 가동된 서버임!")

})

——

 

 

 

 

 

 

 

 

 

— git init —

=> 우선 원격 저장소 login-lecture    생성.

 

1.

Git init

 

2.

nano README.md

=> 작성 후 ctrl + X, 그리고 yes의 Y 입력 후 엔터.

3.

nano .gitignore

=> 작성 후 control + X, 그리고 y 후 엔터

4.

Git add .

 

5.

git remote add origin git@github.com:msdou46/login-lecture.git

 

6.

git push -u origin master

 

7.

cd ..

=> 한 단계 윗 레벨의 폴더로.

 

8.

git clone git@github.com:msdou46/login-lecture.git login-lecture-2

=> clone 연습해보기.

 

9.

git reset HEAD .

=> 커밋 잘못 했을 때 함 해봐. 리셋.

 

 

10.

Sudo npm I nodemon -g

=> 글로벌에서 노드몬 사용.

=> 그다음,

현재 < kimminsoo@gimminsuui-MacBookPro app  > 경로에서

< nodemon ./bin/www.js> 명령어 실행.

=> package.json 에서 “start” 값 바꿔주면 npm start 로 가능.

 

11.

git tag v0.1.0-notDB

=> 중요한 저장 내역은 태그로 관리해 주는 게 좋아.

git log --oneline << 확인해보기.

git push origin v0.1.0-notDB << 원격 저장소에 태그를 푸쉬.

 

 

 

 

— 파일 —

bin

=> 바이너리. 실행 파일들을 모아둔 곳.

 

 

 

 

— 참고 사이트 —

 

https://codepen.io/

=> 로그인 화면 html 참고

 

 

 

 

— 클래스의 static 메소드 —

static 키워드는 클래스의 정적 메서드를 정의한다.

 

정적 메서드는 클래스의 인스턴스 없이 호출이 가능하며 클래스가 인스턴스화되면 호출할 수 없다. 

정적 메서드는 종종 어플리케이션의 유틸리티 함수를 만드는데 사용된다.

 

동일한 클래스 내의 다른 정적 메서드 내에서 정적 메서드를 호출하는 경우 키워드 this를 사용할 수 있다.

 

참고 : https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Classes/static

 

 

 

 

 

— RDS mysql 한글 설정해주기 —

RDS -> 왼쪽 탭 “데이터베이스” -> DB 식별자 < express-database > 클릭해서 들어가기 -> 왼쪽 탭 “파라미터 그룹”

-> 우측 상단 < 파라미터 그룹 생성 > 오렌지 색 버튼 클릭 -> 

 

파라미터 그룹생성.

 

파라미터 그룹 패밀리 - mysql8.0

유형 - DB Parameter Group

그룹 이름 - express-database

설명 - for utf8 setting

 

-> 생성된 파라미터 그룹 “ express-database “ 에 들어가기, 들어간 후 DB 옵션들을 변경해 보자.

-> “ char “ 라고 검색해서 나온 옵션값들의 “값” 을 모두 utf8 로 바꿔줄거야…

-> 우측 상단의 “ 파라미터 편집” 클릭. “값” 필드들을 uft8 로 바꿀 수 있는 것들은 모두 바꿔줘.

-> 아직 “변경 사항 저장” 누르지 말고, 검색창에 이번에는 “ colla” 라고 검색.

collation_connection, collation_server 이 두 개의 값을 “ utf8_general_ci “ 로 변경.

-> 변경 사항 저장

 

-> “데이터베이스” 탭으로 이동, 내가 생성한 인스턴스 “ express-database “ 클릭

-> 우측 상단 “수정” 버튼 클릭

-> “ 데이터베이스 옵션 “ 목록 중 “ DB 파라미터 그룹 “ 을 “express-database” 로 선택.

=> 이렇게 하면 DB의 기본 설정들이 해당 파라미터의 설정으로 변경될거야.

-> 그 다음 계속, 즉시 적용, 인스턴스 수정.

 

해당 Db 인스턴스의 상세 페이지에 들어가서 “구성” 탭을 선택해보면, 아래쪽에 현재 선택된 파라미터 그룹을 확인할 수 있어.

 

 

 

 

— 워크밴치에서 res mysql 연동하기 —

 

1.

워크밴치 실행

 

2.

Mysql connections 문구 옆의 + 버튼 클릭

 

3.

Connection name : express-database

=> 내 맘대로

Hostname : express-database.cop97vlzzz2l.ap-northeast-2.rds.amazonaws.com

=> DB 의 엔드포인트

port: 3306

Username : root

Password -> store in keychain : lololo46

 

 

 

 

 

 

 

— login-lecture 용 DB 만들기 —

 

1.

create database login_lecture

=> *****

sql문 실행 단축키 : command + enter

 

2.

create table users (

id varchar(30) NOT NULL,

    name varchar(30) NOT NULL,

    psword varchar(30) NOT NULL,

    in_date datetime default current_timestamp,

    

    PRIMARY KEY (id)

 );

=> users 용 테이블 생성.

 

 

3.

show tables;

desc users;

=> 테이블 살펴보기.

 

 

 

 

 

— mysql 연동 전 자체 변수로 로그인, 회원가입 구현했을 때의 UserStorage.js --

 

——

"use strict"

 

const fs = require("fs").promises;

        // fs.readFile 는 promise 를 반환하게 될 거야.

 

class UserStorage {

 

    static #getUserInfo (data, id) {

        const users = JSON.parse(data);

        const idx = users.id.indexOf(id);

        const userInfo = Object.keys(users).reduce((newUser, info) => {

            newUser[info] = users[info][idx];

            return newUser;

        }, {});

 

        return userInfo

    }

 

    static #getUsers (data, isAll, fields) {

        const users = JSON.parse(data);

        if (isAll) return users;

 

        const newUsers = fields.reduce((newUsers, field) => {   // 전체 데이터 중 일부 필드만 가져오고 싶을 때.

            if (users.hasOwnProperty(field)) {

                newUsers[field] = users[field];

            }

            return newUsers;

        }, {}); // 전체 데이터 타입. 객체로 반환한다.

        return newUsers;

    }

    

    static getUserInfo (id) {

        return fs.readFile("./src/databases/users.json")

            .then((data) => {

                return this.#getUserInfo(data, id);

            })

            .catch(console.error);

    }

 

    static getUsers (isAll, ...fields) {

        return fs.readFile("./src/databases/users.json")

            .then((data) => {

                return this.#getUsers(data, isAll, fields);

            })

            .catch(console.error);

    }

 

    static async save (userInfo) {

        const users = await this.getUsers(true);

        

        if(users.id.includes(userInfo.id)) {

            throw "이미 존재하는 아이디입니다.";

        }

        users.id.push(userInfo.id);

        users.name.push(userInfo.name);

        users.psword.push(userInfo.psword);

        // 데이터 저장. 그냥 저장하면 기존의 데이터들을 전부 덮어 씌워 버리기 때문에, 일단 모든 데이터를 가져와서 

        // 새로 추가되는 유저 정보를 더한 다음에, 그렇게 완성된 총 데이터를 다시 파일에 넣어야 해.

        fs.writeFile("./src/databases/users.json", JSON.stringify(users));

        return { success: true };

    }

}

 

 

module.exports = UserStorage;

——

 

 

 

 

— 함수는 한 가지 기능만 수행하도록 구현해야 해—

 

Promise로 만들어주지 않으면 하나의 함수에서 DB를 조회하고, 로그인 정보를 검증하고,

클라이언트에 응답하지 해주는 ‘이도 저도 아닌 코드’ 가 만들어 짐.

 

클래스는 User 와 UserStorage 처럼 각자의 역할을 분명하게 구분시켜주는 것이 좋아.

UserStorage 에서는 DB를 CRUD 하는 역할만 수행하고, 해당 데이터를 가지고 검증 및 조작하는 것은

User 가 수행하도록 역할을 구분 짓는 거야.

 

해당 코드에 만족하지 말고, 보다 더 나은 리팩토링을 시도해보자.

 

 

 

 

— dotenv —

 

npm i dotenv

 

우리는 app 폴더 안에 .env 라는 파일을 만들어서 이 안에서 환경변수를 관리해 줄 거야.

 

 

*****

dotenv.config({path: 경로})

=> 이와 같은 식으로 .env의 파일 경로를 지정해줄 수도 있으며,

“env” 가 아닌 다른 파일명으로 사용할 수도 있어. 

그러나 일반적으로 사용 되는 이름으로 하는 것이 의사소통에 있어서도 좋겠지.

 

 

 

 

 

 

 

 

 

— log 관리 —

=> Morgan, winston 이 둘에 대해서 알아볼 거야.

 

1.

morgan

=> npm I Morgan 으로 설치.

 

2.

——

const morgan = require("morgan");

 

const accessLogStream = fs.createWriteStream(

    `${__dirname}/log/access.log`

    , { flags: 'a' }

); // 해당 변수는 src/config/log.js 안에 저장해두고 모듈 익스포츠로 빼와.

// const accessLogStream = require("./src/config/log”) 이렇게.

 

 

app.use(morgan(":method :date[web]", { stream: accessLogStream}));    // morgan 미들웨어 등록.

——

=> 미들웨어에 로그 형식을 등록할 수 있어.

관련 참고 자료는 https://www.npmjs.com/package/morgan

 

 

— src/config/log.js —

——

const fs = require("fs")

const appRoot = require("app-root-path")

 

const accessLogStream = fs.createWriteStream(

    `${appRoot}/log/access.log`

    , { flags: 'a' }

);

 

module.exports = accessLogStream

——

 

 

** 추가.

https://www.npmjs.com/package/morgan

해당 npm 공식 사이트에서 “ log file rotation “ 이라는 항목을 보면,

——

var express = require('express')

var morgan = require('morgan')

var path = require('path')

var rfs = require('rotating-file-stream') // version 2.x

 

var app = express()

 

// create a rotating write stream

var accessLogStream = rfs.createStream('access.log', {

  interval: '1d', // rotate daily

  path: path.join(__dirname, 'log')

})

 

// setup the logger

app.use(morgan('combined', { stream: accessLogStream }))

 

app.get('/', function (req, res) {

  res.send('hello, world!')

})

——

=> 이런 부분이 있어.

rotating-file-stream 라는 모듈을 불러와서, rfs.createStream 으로 스트림을 열어주고,

interval: '1d', 라는 인터벌을 사용하면

하루에 한 개의 로그 파일만 생성하도록 만들 수 있나봐. 이거 좋은 거 같은데?

 

 

 

 

 

 

___________

그 다음으로, winston

 

 

 

1.

morgan 을 app.js 에서 설정해준 것과 달리, winston 은 바로 src > config 안에 logger.js 라는 파일을 만들어 줄거야.

Logger.js 에서 winston 에 대한 로깅 설정들을 작성해주고, app.js 에서는 그냥 로그를 남기기만 하기로.

 

우선 npm I winston 으로 npm 모듈을 다운로드.

 

 

const logger = require('./src/config/logger');      // winston 모듈을 불러온 js 파일.

logger.error("안녕 노드!");

=> 이런 식으로 로그를 남기고 싶다면 logger 를 불러와서 logger.info() 나 logger.error 이런 식으로 로그를 남기자.

——

< www.js >

 

"use strict";

 

const app = require("../app")

const logger = require("../src/config/logger");

const PORT = process.env.PORT || 3000;

 

app.listen(PORT, () => {

    logger.info(`${PORT} 포트에서 서버가 가동되었습니다.`)

});

——

=> 서버 가동 될 때에도 로그를 남기도록.

 

 

 

 

2.

Winston 을 사용해서 날짜별로 로그 파일을 남기는 법.

=> https://www.npmjs.com/package/winston-daily-rotate-file 참조.

 

Npm 모듈 중에 “ winston-daily-rotate-file “ 라는 게 있어.

이걸 사용해서 날짜별로 관리 가능.

옵션 란이 있는데, 여기 것들을 참조해서 만들어 보면 돼.

 

 

 

 

 

 

 

 

— 마지막으로, HTTP 상태 코드 붙여주면서 최적화 —

=> https://developer.mozilla.org/ko/docs/Web/HTTP/Status

=> http 상태코드 참고.

 

1.

우선 디렉토리 구성 정리.

 

bin

=> 노드 프로젝트가 실행되기 위한 실행 파일이 존재.

src

=> 작업한 source 코드들이 들어 있어.

이 안에서 MVC 패턴으로 코드를 작성.

model, controller, view

app.js

=> 메인 파일. 루트 파일.

.env

=> 환경 변수 관리