포스트

노드 학습 8일차

안녕하세요 🐸
휴가 쓰고 공부하는 스스로에게 칭찬 좀 하면서 시작합니다 헤헤

HTTP 서버 만들기

http 모듈을 통해 서버를 만들 수 있습니다. 다음은 그 예제입니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
const http = require('http');

const server = http.createServer((req,res)=>{
    res.write('<h1>Hello Node</h1>');
    res.write('<h1>Hello Server</h1>');
    res.end();
});

server.listen(8080);

server.on('listening',()=>{
    console.log('8080 포트에서 대기 중')
});

server.on('error',(err)=>{
    console.error(err);
})

여기서 createServer() 로 생성된 서버는 listen() 을 통해 포트와 리스너를 할당 받아 실행하는데요 listen() 은 오버로딩 되어 있어 호스트명, 백로그 등의 기타 설정을 사용하기 위해서는 문서를 확인해보는게 좋겠습니다.
예를 들어 제가 작성한 예시에서는 서버에 listening 이라는 이벤트 리스너를 설정했지만 이 부분을 다음처럼 설정할 수 도 있습니다.

1
2
3
4
5
// 생략
server.listen(8080,()=>{
	console.log('8080 포트에서 대기 중')
})
// 생략

express 시작하기

드디어 express를 해봅니다. 갈길이 멀군요
기본적으로 생성 프로그램(혹은 툴 등)을 사용하지 않고 express 프로젝트를 생성하는 방법은 다음과 같습니다.

  1. npm init 으로 프로젝트 초기화
  2. npm i express 명령어로 express 설치

여기까지가 기본이고 추가로 서버의 포트, HTTP 메서드, URI 등은 개발자 작성하기 나름이고 기본 방법은 여기 까지 입니다.
하지만 강의에서 추가로 편의성을 위해 알려준 패키지로 nodemon 이라는 패키지가 있었는데요 해당 패키지는 코드에 변화가 생길 경우 이를 감지하여 자동으로 서버를 재기동해서 개발자의 번거로움을 줄여줍니다.

npm i -D nodemon

으로 설치하여 사용할 수 있으며 nodemon 패키지를 사용하기 위해서 package.json을 편집해야하는데 아래의 예제처럼 입력하면 사용할 수 있습니다.

1
2
3
4
5
6
7
8
{
//생략
  "scripts": {
    "start":"nodemon app", // 추가된 스크립트 부분
    "test": "echo \"Error: no test specified\" && exit 1"
  },
//생략
}

이처럼 입력하여 npm run start 를 입력하면 nodemon 에서 서버를 실행하여 감지하고 재기동까지 합니다.

express 기본 사용 방법

express를 사용하기 위한 기본적인 방법은 다음의 예시와 같습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
const express = require('express'); // 익스프레스 모듈을 require하여 받습니다.
const path = require('path'); // 경로 관리를 위한 모듈 path 도 받습니다.


const app = express(); // express application을 생성합니다.

app.set('port',process.env.PORT | 3000); // 포트를 설정합니다

app.get('/',(req,res)=>{ // GET 방식의 / 에 대한 응답을 설정합니다.

	/**
	 * html 파일을 제공할 경우 sendFile() 을 사용합니다.
	 * 이 때 내부적으로는 fs 모듈의 기능을 사용합니다.
	*/
    res.sendFile(path.join(__dirname,'index.html'));
})

app.post('/',(req,res)=>{
    res.send('hello express');
})

app.get('/about',(req,res)=>{
    res.send('hello express');
})

app.listen(3000,()=>{
    console.log('익스프레스 서버 대기중')
})

패키지 사용 여부 확인하기

npm ls {패키지명}

현재 어떠한 패키지가 사용 중인지 확인할 수 있습니다.
버전이 잘못되었던가 하는 문제도 같이 나옵니다!

미들웨어 사용하기

특정 혹은 모든 라우터가 수행되기 전에 동일하게 수행되어야하는 작업이 있을 경우에 사용할 수 있는 기능입니다.
예를 들어 모든 라우터에 대해 권한을 체크해야할 경우 권한 체크 하는 코드가 반복될 수 있는데요, 이런 부분을 미들웨어를 통해 깔끔하고 손쉽게 정리할 수 있습니다.
심지어 모든 라우터가 아닌 특정 라우터에 대해서만 실행되도록 할 수 있습니다.

다음은 코드 예제입니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
//생략
/** use()는 미들웨어를 장착하는 함수로써 세번째 인자인 next를 필수로 사용해야합니다.
 * next()를 사용하지 않으면 다음으로 넘어가지 않아 미들웨어까지의 동작만 하고 멈추게 됩니다.
 * 여기서 다음이란 라우터를 찾는 행위 뿐만 아닌 다음 미들웨어로 넘어가는 동작을 포함합니다.
 */
app.use((req,res,next)=>{ //세번째 인자인 next 존재 확인
    console.log('어디서든 동작하는 첫번째 미들웨어');
    next(); // 다음 미들웨어 호출
}, (req,res,next)=>{ 
    console.log('어디서든 동작하는 두번째 미들웨어');
    next(); // 다음 미들웨어 호출
},(req,res,next)=>{ 
    console.log('어디서든 동작하는 세번째 미들웨어');
    next(); // 다음 미들웨어가 없기 때문에 경로 찾음
})

/**
 * 위의 use에서는 모든 라우터에 대한 미들웨어를 사용했지만
 * 여기서는 '/about' 으로 오는 요청에 대해서만 동작하는 미들웨어 입니다.
 */
app.use('/about',(req,res,next)=>{
    console.log('/about 으로 가는 미들웨어 입니다');
    next();
})
//생략

에러 핸들링 하기

express에서도 에러는 핸들링해줘야합니다. 단, 기본적으로 express에서 에러를 처리해주긴 합니다.
그럼에도 불구하고 에러 핸들링을 따로 해주는 이유는 express에서 처리해주는 에러 핸들링은 너무나도 상세한 정보를 보여줘서 보안 위험성이 있기 때문입니다.
에러 핸들링도 express에서는 미들웨어로 처리하게 되는데요 미들웨어의 구조적 순서는 다음과 같습니다.

  1. express 앱 생성
  2. 포트 번호 등의 값 설정
  3. 미들웨어 설정
  4. 라우터 설정
  5. 404 페이지
  6. 에러 처리 미들웨어 설정
  7. 앱 listen 시작

그렇기 때문에 에러 처리 미들웨어는 하단부에 작성하게 됩니다.
다음은 그 예시입니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 미들웨어, 라우터 등 작성 코드 생략

/**
 * 에러 핸들링을 위한 미들웨어는 반드시 4개의 인수를 필요로함
 * status 500 에러임을 명시합니다. 설정하지 않을 경우 기본값(200) 으로 전달됩니다
*/
app.use((err,req,res,next)=>{
	console.error(err);
    res.status(500).send('<h1>에러가 났어요...</h1>')
})

app.listen(3000,()=>{
	console.log('익스프레스 대기 중!');
})

에러 처리 미들웨어의 경우 반드시 4개의 인수를 가져야합니다. 반복되는 use의 사용 구조를 보면 알겠지만 use 함수 자체가 오버로딩되어 있어 함수의 갯수에 따라 아예 다른 함수로 취급되기 때문에 에러 핸들링 미들웨어는 반드시 4개의 인수를 필요로 합니다.

404 페이지 커스텀하기

클라이언트가 라우터에 없는 URI를 요청한 경우 서버는 404 페이지를 전달해줍니다. express의 경우에는 빈화면에

Cannot {HTTP METHOD} {URL}

형식으로 글을 띄워줍니다. 이 부분도 미들웨어를 통해 커스텀 할 수 있습니다.
위치는 라우터 작성 후, 에러 핸들링 전에 작성해줍니다.

1
2
3
4
5
6
7
8
9
10
11
12
// 미들웨어 및 라우터 작성 코드

/**
 * 해당하는 라우터가 없을 경우 발생하는 404 페이지에 대응하는 미들웨어 입니다.
 * 에러 핸들링 미들웨어보다는 상단에 위치 하되, 라우터 작성 코드보다는 하단에 작성합니다.
 * status는 404임을 명시해줍니다. 설정하지 않을 경우 기본값(200) 으로 전달됩니다.
 */
app.use((req,res,next)=>{
    res.status(404).send('<h1>해당하는 URI가 없네요...</h1>');
})

// 에러 미들웨어 및 서버 실행

응답을 보내는 경우 주의할 점

클라이언트와 서버는 하나의 요청에 하나의 응답을 주는 것이 기본이기 때문에 한번에 여러번 응답을 하는 경우 에러가 발생합니다.
response 객체에서 응답을 주는 함수는 다음의 종류가 있습니다.

  1. send()
  2. sendFile()
  3. json()
  4. render() 그리고 이처럼 응답을 주는 함수는 미들웨어의 next()와 함께 사용할 수 없습니다.

next 사용 시 특수한 몇 가지 경우

미들웨어에서 next는 매우 중요합니다. 다음 미들웨어로 넘어가게 해주기 때문에 없으면 동작이 멈추게 됩니다.
그런데 이 next는 인수 전달의 여부, 어떤 인수를 넘기느냐에 따라 특수하게 동작하는 경우가 있습니다.

인수를 전달하는 경우

이 경우 next에 전달된 인수는 에러로 판단되어 에러 처리 미들웨어로 넘어가게 됩니다.

문자열 ‘route’ 를 전달하는 경우

다음과 같은 라우터가 있다고 가정해보겠습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
app.get('/',(req,res,next)=>{ // GET /
	if({조건}){
		next('route');
	} else {
		next();
	}
},(req,res)=>{
	console.log("조건이 false가 되어 next()가 수행 되는 경우 여기로 옵니다")
})

app.get('/',(req,res)=>{ // GET / (위와 동일)
	console.log("조건이 true가 되어 next('route') 가 수행되면 여기로 옵니다.")
})

여기서 코드를 보고 유추할 수 있듯이 문자열 ‘route’ 가 인수로 전달된다면 다음 미들웨어로 넘어가지 않고 다음 라우터를 찾게 됩니다.

이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.