본문 바로가기

WINK-(Web & App)/Express.js (Node.js) 스터디

[2024 여름방학 Node.js 스터디] 이종윤 #4주차

반응형

NPM(Node Package Manager)

: Node.js의 패키지를 관리할 수 있는 도구이다. Node.js에서 사용할 수 있는 모듈들을 패키지화하여 모아둔 저장소 역할과 패키지 설치 및 관리를 위한 CLI(Command line interface)를 제공한다. 자신이 작성한 패키지를 공개할 수도 있고 필요한 패키지를 검색하여 재사용할 수도 있다.

* 명령줄 인터페이스(CLI)는 키보드를 이용해 운영 체제와 상호 작용하는 소프트웨어 메커니즘이다.

NPM사용법

먼저 npm을 사용하기 위해서는 npm을 설치하기 전에 먼저 package.json이라는 파일을 만들어야한다.

package.json라는 파일은 설치된 패키지들을 보여주고 패키지들의 버전을 관리하는 파일이다.

 

1. 우선 콘솔창에 ' $ npm init '를 친다

2. 상세 정보를 친다.(밑에 표로 설명)

package.json

설치가 되면 이러한 모습으로 보인다.

 

<package.json 속성 설명>

package name 패키지의 이름입니다. package.json의 name 속성에 저장됩니다. name
version 패키지의 버전입니다. npm의 버전은 다소 엄격하게 관리됩니다. 5.3절에서 다룹니다. version
entry point 자바스크립트 실행 파일 진입점입니다. 보통 마지막으로 module.exports를 하는 파일을 지정합니다. package.json의 main 속성에 저장됩니다. main
test command 코드를 테스트할 때 입력할 명령어를 의미합니다. package.json scripts 속성 안의 test 속성에 저장됩니다. scripts.test
git repository 코드를 저장해둔 깃(Git) 저장소 주소를 의미합니다. 나중에 소스에 문제가 생겼을 때 사용자들이 이 저장소에 방문해 문제를 제기할 수도 있고, 코드 수정본을 올릴 수도 있습니다. repository
keywords 키워드는 npm 공식 홈페이지(https://npmjs.com)에서 패키지를 쉽게 찾을 수 있게 합니다. package.json의 keywords 속성에 저장됩니다. keywords
license 해당 패키지의 라이선스를 넣으면 됩니다. license

 

만약 package.json의 내용이 잘못되었다면 그냥 파일에 들어가서 글자를 바꾸면 된다.

 

이제 콘솔에 ' $ npm install [패키지명] '을 입력하면 npm이 설치된다.

$ npm install express를 하면 dependencies에 등록된다.

이렇게

 방금 express를 설치했습니다. 이때 프로젝트 이름(package.json의 name, 현재 npmtest)은 express여서는 안 됩니다. 앞으로 많은 패키지를 설치할 텐데 그때마다 프로젝트 이름과 겹치지 않는지 확인해야 합니다.

의존관계

: 모듈이 다른 모듈을 사용할 수 있는 것처럼, 패키지가 다른 패키지를 사용할 수도 있다.

* 지금처럼 내 노드에 남이 만든 express를 사용해 만들었으니 내꺼도 express에 의존관계인 것이다. 

그런데 이 express패키지도 여러 패티지들에 의존해 있다. (express를 하나만 다운받아도 여러 패키지가 들어온다.)

이렇게 패키지 하나가 여러 패키지에 의존하고 또 그 패키지가 다른 패키지들에 의존한다.

이렇게 관계가 매우 복잡하니 package.json이 필요하다.

의존관계

 

 

모듈이 다른 모듈을 사용할 수 있는 것처럼, 패키지가 다른 패키지를 이용할 수 있다.

이러한 관계를 의존관계라고 한다.

개발용 패키지

실제 배포 시에는 사용되지 않고, 개발 중에만 사용되는 패키지들이다.

: npm install --save-dev [패키지] [...]로 설치한다. 

* 그리고 devDependencies 속성이 새로 생겨 이 속성에서는 개발용 패키지들만 따로 관리합니다.

전역(global) 설치

: 패키지를 현재 폴더의 node_modules에 설치하는 것이 아니라 npm이 설치되어 있는 폴더에 설치한다. 이 폴더의 경로는 보통 시스템 환경 변수에 등록되어 있으므로 전역 설치한 패키지는 콘솔의 명령어로 사용할 수 있다.

: 콘솔에 ' $ npm install --global [패키지명] '으로 설치하면 된다.

 

npm install 명령어는 npm i로 줄여 쓸 수 있습니다. --save-dev 옵션은 -D로, --global 옵션은 -g로 줄여 써도 됩니다.

npx

전역설치를 하면 전역 설치한 패키지는 package.json에 기록되지 않아 다시 설치할 때 어려움이 있다.

그렇다면 모듈을 package.json의 devDependencies 속성에 기록한 후, 앞에 npx 명령어를 붙여 실행하면 된다.

그러면 패키지를 전역 설치한 것과 같은 효과(명령어로 사용 가능)를 얻을 수 있고 패키지가 package.json에 기록되었으므로 버전 관리도 용이하다. 

패키지 버전

: 노드 패키지들의 버전은 항상 세 자리로 이뤄져 있다. 버전이 세 자리인 이유는 SemVer 방식의 버전 넘버링을 따르기 때문이다. (SemVer는 Semantic Versioning(유의적 버전)의 약어이다. 버전을 구성하는 세 자리가 모두 의미를 갖고 있다는 뜻이다.)

- 각각의 패키지는 모두 버전이 다르고 패키지 간의 의존 관계도 복잡하다. 어떤 패키지의 버전을 업그레이드했는데, 그것을 사용하는 다른 패키지에서 에러가 발생한다면 문제가 된다. 따라서 버전 번호를 어떻게 정하고 올려야 하는지를 명시하는 규칙이 등장했는데 이것이 바로 SemVer이다.

SemVer

npm 명령어들

명령어 설명
npm update [패키지 이름] 특정 패키지를 업데이트합니다.
npm update 업데이트 가능한 모든 패키지를 Wanted에 적힌 버전으로 업데이트합니다.
npm uninstall [패키지 이름] 해당 패키지를 제거합니다. npm rm [패키지 이름]으로 줄여 쓸 수 있습니다.
npm search [검색어] npm의 패키지를 검색합니다. GUI가 없는 리눅스에서는 유용합니다.
npm info [패키지 이름] 패키지의 세부 정보를 파악할 때 사용하는 명령어입니다.
npm login npm 로그인을 위한 명령어입니다.
npm whoami 로그인한 사용자를 확인합니다.
npm logout 로그인한 계정을 로그아웃합니다.
npm version [버전] package.json의 버전을 올립니다.
npm version major major 버전을 1 올립니다.
npm version minor minor 버전을 1 올립니다.
npm version patch patch 버전을 1 올립니다.
npm deprecate [패키지 이름] [버전] [메시지] 해당 패키지를 설치할 때 경고 메시지를 띄웁니다.
npm publish 자신이 만든 패키지를 배포합니다.
npm unpublish 배포한 패키지를 제거합니다. 24시간 이내에 배포한 패키지만 제거할 수 있습니다.

npm 배포하기

우선 본인의 패키지를 배포하기 전에 npm 계정이 있어야한다.

계정을 만들었으면 npm publish 명령어를 사용해서 배포하면 된다.

$ npm publish
// notice 생략
npm ERR! code E403
npm ERR! 403 403 Forbidden - PUT https://registry.npmjs.org/npmtest-1234 - You cannot publish over the previously published versions: 0.0.1.

만약 이런 오류가 뜬다면 이 미 출시한 버전이라는 뜻이다.

npm version 이란 명령어를 사용해 올릴 자리를 정해 버전을 수정해주면 된다.

 

※ 추가로 npm은 패키지 명이 겹치면 안된다.

 

+ npm이 너무 많아서 어떤게 쓸만 한지 잘 모르겠을 때는 npm trends 사이트에 들어가서 다운로드 수가 많은 것, 업데이트가 비교적 최근에 된 것이 안전하고 믿을 만하다.

익스프레스(express)

: 서버를 제작하는 과정에서 겪게되는 불편을 해소하고 편의기능을 추가한 웹 서버 프레임워크이다.

 

우선 얘도 npm이니 콘솔에 npm init을 해준다.

추가로 nodemon도 개발자용으로 깔아준다.

이 노드몬은 스크립트에 넣으면 수정사항이 생길 때마다 app.js 서버를 재실행 해준다.

이 npm을 개발자용으로 두라는 이유는 서버를 배포한 후에는 서버를 수정할 일이 별로 없기 때문이다.

"scripts": {
  "start": "nodemon app.js"
}

 

+ package.json 파일은 Node.js 프로젝트의 메타데이터를 담고 있는 파일이며, 프로젝트의 이름, 버전, 설명, 저자 등의 정보와 사용하는 패키지의 목록을 저장한다. 또한 package.json 파일의 scripts 항목을 통해 다양한 명령어를 설정할 수 있다. 

const express = require('express');

const app = express();

우선 Express모듈을 실행한다.

Express모듈 내부에서 http모듈이 내장되어있어 서버역할을 할 수 있다.

app.get('/', (req, res) => { res.send('Hello, Express'); });

루트 경로(/)에 대한 GET 요청을 처리하는 라우트를 설정한다. 클라이언트가 / 경로로 GET 요청을 보내면, 서버는 "Hello, Express"라는 응답을 보낸다.

  • 루트 경로(root path)는 웹 애플리케이션에서 가장 기본이 되는 경로를 의미한다. 이는 URL에서 도메인 이름 뒤에 오는 첫 번째 경로이며, 보통 /로 표시된다. 루트 경로는 웹사이트나 웹 애플리케이션의 최상위 페이지에 해당한다.
  • 매개변수 앞쪽은 라우터의 범위를 지정하는 것인데 없으면 전범위이고 범위가 넓을 수록 뒤에 적어야한다.
  • 한 라우터에 res.send()는 여러번 사용하면 안된다.
  • res.send()는 res.status(200)send()이 생략된 것이라 서버에서 이 숫자를 조정하면 브라우저에게 구라를 칠 수 있다.
기능 설명
app.set('port', 포트) 서버가 실행될 포트를 설정한다. process.env 객체에 PORT 속성이 있다면 그 값을 사용하고, 없다면 기본값으로 3000번 포트를 이용한다.
app.get(키) app.set으로 저장된 데이터를 가져온다.
app.get(주소, 라우터) 지정한 주소에 대한 GET 요청이 올 때의 동작을 정의한다. 매개변수 req는 요청 정보를 담고 있으며, res는 응답 정보를 담고 있다.
res.send 응답을 전송한다. res.write나 res.end 대신 사용한다.

그리고 이 res.send를 html파일로 응답할 수 있다.

path모듈을 사용하여 상대경로로 파일위치를 지정해주면 된다.

미들웨어

: 요청과 응답의 중간에 위치하기때문에 미들웨어라고 불린다. (라우터와 핸들러도 미들웨어의 일종이다.)

: 요청과 응답을 조작해 기능을 추가하기도 하고, 나쁜 요청을 걸러내기도 한다.

코드 구문설명
app.use(미들웨어) 모든 요청에서 미들웨어를 실행한다.
app.use('/abc', 미들웨어) /abc로 시작하는 요청에서 미들웨어를 실행한다.
app.post('/abc', 미들웨어) /abc로 시작하는 POST 요청에서 미들웨어를 실행한다.

이렇게 미들웨어는 app.use(미들웨어)꼴로 사용된다.

next

: 그러니까 미들웨어는 조건이 맞는 모든 라우터 중간에 들어가서 실행되는 것이다.

: 그런데 next없이 쓰면 다음 명령어로 넘어가지 않고 바로 다음 라우터로 넘어간다.

app.use((res, req, next) => {
	console.log('모든 요청에서 실행하고 싶어요');
    next();
})

그래서 이렇게 적어야 한다.

미들웨어는 함수하고 비슷한 것이다.

app.use((res, req, next) => {
	console.log('모든 요청에서 실행하고 싶어요');
    next();
}, (res, req, next) => {
	console.log('모든 요청에서 실행하고 싶어요');
    next();
}, (res, req, next) => {
	console.log('모든 요청에서 실행하고 싶어요');
    next();
})

이렇게 반복해서 써도 되고 next를 써서 계속 다음꺼로 넘어간다.

error

: 에러미들웨어도 있다.

-> 실제 서비스 중 에러가 발생하면 리액트에서 처리를 해주지만 그 정보가 너무 자세히 노출되어 정보가 노출 될 수 있다. 그래서 서버에서는 에러처리가 중요하다.

app.use((err, res, req, next) => {
	console.error(err);
    res.send('에러가 발생했습니다.');
})

그리고 노드는 자바스크립트이기에 에러처리에서 매개변수를 4개 다 써야한다.

morgan

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

app.use(morgan('combined'));
//더 자세하다.

이렇게 사용하면 되고 morgan는 요청과 응답에 대한 정보를 콘솔에 기록하는 미들웨어이다.

cookieParser

: http에서 쿠키를 파싱하기위해 지저분하게 쓰던 코드들을 간단하게 만들 수 있게 도와주는 미들웨어이다.

const cookieParser = require('cookie-parser');

app.use(cookieParser());

app.get('/', (res, req, next)) => {
	req.coockies // {mycookie : 'test'}
    res.cookie(name, encodeURIComponent(name), {
    	express: new Date(),
        httpOnly: true,
        path:'/',
    })
    res.clearCookie(name, encodeURIComponent(name), {
        httpOnly: true,
        path:'/',
    })
    res.sendFile(path.join(__dirname, 'index.html'));
})

원래 엄청 길었던 http모듈 코드를 이렇게 짦게 보기 좋게 줄일 수 있게 되었다.

body-parser

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

app.use(express.json());
app.use(express.urlencoded({ extended: true }));

요즘은 이렇게 사용된다.

static

: static 미들웨어는 정적인 파일들을 제공하는 라우터 역할을 한다.

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

app.use('/', express.static(path.join(__dirname, 'public')));

<예시>

  • 요청경로: localhost: 300/jyjjang.html
  • 실제경로: express-test/public/jyjjang.html

※ 미들웨어간 순서 또한 매우 중요하다!!!

express-session

: 세션 관리용 미들웨어이다.

-> 개인의 요청에 각자 고유의 저장공간을 만들어주는 느낌이다.

const session = require('express-session');

app.use(session({
  resave: false,
  saveUninitialized: false,
  secret: process.env.COOKIE_SECRET,
  cookie: {
    httpOnly: true,
    secure: false,
  },
  name: 'session-cookie',
}));
코드 설명
req.session.name = 'zerocho'; 세션에 name이라는 키를 추가하고 값으로 'zerocho'를 설정한다.
req.sessionID; 현재 세션의 ID를 확인한다.
req.session.destroy(); 현재 세션을 완전히 삭제합니다. 세션에 저장된 모든 데이터를 제거한다.

multer

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

(  멀티파트 형식이란 다음과 같이 enctype multipart/form-data인 폼을 통해 업로드하는 데이터의 형식을 의미한다. )

<form action="/upload" method="post" enctype="multipart/form-data">
  <input type="file" name="image" />
  <input type="text" name="title" />
  <button type="submit">업로드</button>
</form>

이것은 body-parser가 해석하기 어렵기 때문에 multer 패키지가 필요하다.

$ npm i multer
const multer = require('multer');

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 },
});

 

 

storage: 속성에는 어디에(destination) 어떤 이름으로(filename) 저장할지
- destination: uploads 폴더에 저장한다.
- filename: [파일명 + 현재시간.확장자] 형식으로 저장해 파일명 중복을 방지한다.
- req는 요청 정보, file은 업로드된 파일 정보를 다루며, done 함수로 가공된 경로나 파일 이름을 전달한다.

 

limits: 업로드에 대한 제한 사항을 설정
- fileSize: 업로드 파일 크기를 5MB로 제한한다.

app.use(upload.single('image'))

- 파일을 하나만 업로드하는 경우

app.use(upload.array('images'))

- 여러 정보를 업로드하는 경우

app.use(upload.fields([{ name: 'image1' }, { name: 'image2' }]))

- 여러 정보, 이름을 다 다르게 지정하는 경우

app.use(upload.none())

- 파일을 업로드하지 않고 멀티파트 형식으로만

multer의 미들웨어

Router객체

: 이 객체를 사용하면 지저분한 라우터를 분리하여 라우팅을 깔끔하게 관리할 수 있다.

 

그냥 js폴더를 만들고

const express = require('express');

const router = express.Router();

// GET / 라우터
router.get('/', (req, res) => {
  res.send('Hello, Express');
});

module.exports = router;

이렇게 쓰면 된다.

app.use('/', indexRouter);

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 상태 코드를 지정한다.
404 error
반응형