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.opptionslisten : 포트를 연결하고 서버를 실행
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
프론트엔드에 필요한 기술. 필요하면 다시 체크