2022.09.19 ~ 20 개인 보충학습 - 22.09.16 경일 메타버스 24주차 4일 수업내용. Node.js - npm 패키지 매니저, 익스프레스
p. 208 ~ 209
Node Package Manager의 약어
특정 기능의 패키지를 찾아 설치 가능
패키지가 다른 패키지를 사용 → 의존 관계
p. 209 ~ 218
package.json : 설치한 패키지의 버전을 관리하는 파일
패키지 하나가 다른 여러 패키지에 의존
→ 복잡하게 얽히는 의존 관계
→ 그래서 이를 모두 관리하는 package.json이 필요
package-lock.json : 패키지들의 정확한 버전과 의존 관계 저장
명령어를 등록해두고 사용 가능
ex. start
명령어에 node [파일명]
을 저장하고 npm start
로 실행
start
나 test
같은 스크립트는 run
을 붙이지 않아도 실행 가능명령어
npm install [패키지 이름]
: 패키지를 설치하는 명령어개발용 패키지 설치
실제 배포에는 사용되지 않고 개발 중에만 사용되는 패키지
명령어
npm install —save-dev [패키지] […]
—save-dev
키워드가 개발용 패키지임을 가리킨다.전역 (Global) 설치
패키지를 npm이 설치되어 있는 폴더에 설치
명령어로 사용하기 위해 행한다.
명령어
npm install —global [패키지] […]
—global
키워드가 전역 설치임을 가리킨다.
전역 설치를 하지 않고 명령어로 사용
전역 설치한 패키지는 package.json에 기록되지 않아 다시 설치하기 어려움
명령어 npx
npx
를 붙여 실행명령어 줄여쓰기
npm install
→ npm i
—save-dev
→ -D
—global
→ -g
p. 218 ~ 220
SemVer 방식
노드 패키지 버전 방식
Semantic Versioning (유의적 버전)의 약어
패키지 간 복잡한 의존 관계에 따른, 버전 업그레이드로 인한 에러를 방지하기 위함
자릿수
major 버전
하위 호환이 안 될 정도로 패키지의 내용이 수정됨
업데이트를 했을 때 문제가 발생할 확률이 높다.
0 → 초기 개발 중, 1 이상 → 정식 버전
minor 버전
하위 호환이 되는 기능 업데이트
업데이트를 했을 때 문제가 없어야 한다.
patch 버전
기존 기능에 문제가 있어 수정
업데이트를 했을 때 문제가 없어야 한다.
수정 사항이 생기면 자릿수의 의미에 맞게 올려 새로운 버전을 배포
→ 기존 버전은 절대 수정하지 않는다.
장점
배포된 버전 내용이 변하지 않아 패키지 간 의존 관계에 큰 도움
패키지 버전만 보고도 에러 발생 여부 가늠이 가능
major → 주의
그 외 → 신뢰 가능
package.json의 경우, 추가 문자로 설치 / 업데이트 정보를 제공해준다.
^
: minor 버전까지만 설치 / 업데이트 가능
ex. npm express@^1.1.1
다른 표현 - 1.x.x
~
: patch 버전까지만 설치 / 업데이트 가능
ex. npm express@~1.1.1
다른 표현 - 1.1.x
>
/ <
/ > =
/ < =
/ =
: 초과 / 미만 / 이상 / 이하 / 동일 버전의 설치 / 업데이트 가능
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, 템플릿 엔진-에러 처리 미들웨어)
요청과 응답에 대한 정보를 콘솔에 기록
app.use(morgan('dev'));
인수 : dev, combined, common, short, tiny
정적인 파일들을 제공하는 라우터 역할
app.use('요청 경로', express.static('실제 경로');
함수의 인수로 정적 파일들이 담겨 있는 폴더 지정
서버의 폴더 경로와 요청 경로가 다르므로 외부에서 서버의 구조 파악이 어려움
⇒ 보안상 이득
파일을 읽을 필요 없이 제공
파일이 없다면 next()
호출, 있다면 호출 X
요청의 본문에 있는 데이터를 해석하여 req.body
객체로 만들어주는 미들웨어
보통 폼 데이터나 AJAX 요청 데이터 처리
멀티파트 (이미지, 동영상, 파일) 데이터는 처리 불가
예시
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
요청에 동봉된 쿠키를 해석해 req.cookie
객체로 만드는 미들웨어
app.use(cookieParser(비밀키));
쿠키를 생성할 때 쓰이는 것은 아니다.
signed
옵션 : true로 설정하면 서명이 붙는다.
세션 관리용 미들웨어
세션을 구현하거나 특정 사용자를 위한 데이터를 임시 저장할 때 유용
인수로 세션에 대한 설정을 받는다.
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);
}
});
이미지, 동영상 등 여러 가지 파일들을 멀티파트 형식으로 업로드할 때 사용하는 미들웨어
멀티파트 형식 : enctype
이 multipart/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>
- 프로젝트 시작으로 시간 부족 : 후에 내용 전부 정리 예정
p. 257 ~ 275
프론트엔드에 필요한 기술. 필요하면 다시 체크