티스토리 뷰

728x90
반응형

앞선 포스팅에서 Node.js를 개발하기 위한 환경 구성방법에 대해 살펴보았다.

개발 환경 구성 방법에 대해 살펴보고자 할 경우 아래 URL을 참고한다.

 

Visual Studio Code(VSCode) 개발환경 구성하기

 

Node.js는 Node 기반으로 동작하는 하나의 작은 웹서버라고 볼 수 있다. NodeJS는 JavaScript를 기반으로 Server Side 개발은 물론 Front End까지 책임질 수 있는 하나의 웹 애플리케이션 형태를 구성할 수 있다.

본 포스팅에서는 Node.js HelloWorld를 호출하는 방법에 대해 살펴보도록 하자.

 Hello World 

간단한 샘플코드를 기반으로 Hello World를 호출하는 Node.js를 생성해 보도록 하자.

 

# 본 가이드에서는 EJS Node Module을 사용하지만, 전체적인 구성을 확인하고자, EJS Sample Template을 생성하여 구성하지 않고 직접 모든 디텍토리 및 구성파일, JavaScript 등을 생성하여 테스트를 진행한다.

 

먼저 코드를 작성하기에 앞서 디렉토리 구조부터 살펴보자.

기본으로 위와 같은 디렉토리 구조를 갖도록 작성한다.

- app.js : app.js는 전체 공통으로 적용할 모듈과 initialize, variable, node listen 정보 등을 설정하며, 특히 Node.js로 유입하는 요청을 관리하는 ingress 역할을 담당한다. app.js가 router 역할을 수행할 수 있지만, 가독성과 유지보수 효율성을 위해 분리하여 관리한다.

- package.json : Maven dependency 관리를 위한 pom.xml과 같이 Node Module의 디펜던시를 관리하는 파일이다.

- node_modules : node module이 저장되는 공간이다. npm install로 설치되는 dependencies package가 위치한다.

- public : static 파일을 위치시킨다.

- router : app.js에서 분리된 세분화된 route rule을 정의한다.

- views : ejs가 저장되는 공간이다.

app.js


먼저 app.js를 작성해 보도록 하자.

var express = require('express')
var app = express()
var router = require('./router/index')

app.listen(3000, function () {
    console.log("start!! express server on port 3000")
});

app.use(express.static('public'))
app.set('view engine', 'ejs')
app.use(router)

위와 같이 app.js를 생성한다. 위 항목을 각각 살펴보도록 하자.

1) var express = require('express')

node는 웹 개발 기능을 지원하지 않는다. 따라서 HTTP 요청 시 이를 처리하기 위한 코드가 추가되어야 하며, 이는 유지보수 효율성을 저하시키는 요소 중 하나이다.

node에서 이러한 웹 개발 기능을 제공하기 위한 것이 바로 express 이다.

express는 HTTP 요청(GET, POST 등)을 처리하는 Handler를 구성하여 Routing 처리 및 미들웨어 웹 프레임워크로써 존재한다. 즉 express를 사용하는 것은 미들웨어 함수를 호출하는 것과 같다고 볼 수 있다.

미들웨어 함수는 req, res, next로 구성된 variable을 갖으며, 아래와 같은 다양한 미들웨어 인스턴스에 바인딩할 수 있다.

express는 특히 cookie, session, login, post data, security header, url parameter 등과 같은 웹 개발 기능들을 패키징한 수많은 라이브러리를 제공하고 있으며, 이를 활용할 수 있다.

express 애플리케이션은 몇가지 유형의 미들웨어를 사용할 수 있다.

- 애플리케이션 레벨 미들웨어 : var app = express() 인스턴스에 바인딩되며, app.use() 및 app.METHOD()로 애플리케이션 미들웨어를 인스턴스에 바인딩할 수 있다. METHOD는 HTTP Method를 정의할 수 있으며, get, post, listen 등을 사용할 수 있다.

- 라우터 레벨 미들웨어 : var router = express.Router() 인스턴스에 바인딩되며, router.use() 및 router.METHOD()로 라우터 레벨 미들웨어를 로드할 수 있다.

- 오류 처리 미들웨어 : 동일한 방법으로 사용할 수 있지만, err, req, res, next 총 4개의 variable을 갖는다는 점이 차이점이다.

- 기본 제공 미들웨어 : express.static(/path, Option)로 정의하며, Express가 제공하는 유일한 기본 제공 미들웨어 함수이다.

Express에 대한 자세한 설명은 다음을 참고하도록 한다.

https://expressjs.com/ko/guide/writing-middleware.html

 

Express 앱에서 사용하기 위한 미들웨어 작성

Express 앱에서 사용하기 위한 미들웨어 작성 개요 미들웨어 함수는 요청 오브젝트(req), 응답 오브젝트 (res), 그리고 애플리케이션의 요청-응답 주기 중 그 다음의 미들웨어 함수 대한 액세스 권한�

expressjs.com

 

2) app.listen(3000, ~)

var express = require('express')
var app = express()
...
...
...
app.listen(3000, function () {
    console.log("start!! express server on port 3000")
});

위 코드는 애플리케이션 레벨의 미들웨어를 적용하였다. ingress 처리를 할 node 기동 port를 지정하는 방식이다.

 

# CallBack Function (콜백함수)

이후 굉장히 많은 부분에서 등장하겠지만, Node.js에서는 CallBack 함수를 다양하게 사용한다.

JavaScript에서 Function은 하나의 Object로 관리된다. 이는 하나의 변수로써 파라미터로써 또는 return으로써 사용될 수 있다. 그냥 쉽게 String을 활용할 수 있는 곳에 Function이 같은 역할로써 동작할 수 있다는 의미이다.

CallBack 함수는 바로 또 다른 함수의 매개변수로 사용되는 함수를 의미한다.

 

아래와 같이

app.listen(3000, function() {

~~~~

});

매개변수로써의 function이 바로 콜백함수이다.

 

CallBack 함수는 JavaScript의 Single Thread 방식을 개선하는 한가지 방안이 될 수 있다.

일반적으로 Sync 방식의 경우 2개 이상의 Method 간 커뮤니케이션이 발생하는 Dependencies가 존재할 경우 하나의 서비스 장애는 또 다른 서비스의 장애로 전파되는 구조이다.

CallBack 함수는 이와 같이 함수 간 결합도를 낮추기 위해 비동기 방식의 처리 프로세스를 갖는다. 

CallBack 함수를 통해 동작을 구현할 경우 Sequencial하지 않도록 Async 기술을 적용할 수 있다.

콜백함수를 이용하여 동작을 구현하면 처리가 끝날 때까지 기다리는 것이 아니라 처리가 끝나는 시점에서 함수를 호출한다. 즉, 정말로 필요할 때만 함수를 호출해서 효율이 좋고 웹사이트에서도 여러 가지 동작을 동시에 할 수 있다.

 

3) app.use(express.static('public'))

위 코드는 기본 제공 미들웨어를 적용하였다. static 파일이 위치하는 디렉토리를 /public으로 지정한다.

 

4) app.set('view engine', 'ejs')

응답 페이지를 독립적으로 작성할 수 있도록 하는 node.js의 view engine을 사용할 수 있다. view engine으로 반환하는 응답 페이지를 Template Document라고 하며, Template Document에서 데이터 변수의 값을 노출할 수 있는 기능을 제공한다.

대표적으로 EJS와 PUG가 있다.

- EJS : Effective JavaScript Templating / HTML 문서를 그대로 사용하기 때문에 익숙하며, 문법적 오류에 유연하다.

- PUG : < > 기호까지도 없앤 간결화 된 키워드를 사용한다.

본 포스팅에서는 EJS View Engine을 사용하여 테스트를 진행해 나갈 것이다.

 

5) app.ues(router)

...
var router = require('./router/index')
...
app.use(router)

위 코드는 라우터 레벨의 미들웨어를 적용하였다. routing을 정의하는 router/index.js 파일을 참조하도록 구성한다.

router/index.js


다음은 router를 정의하는 index.js 파일을 살펴보자.

var express = require('express')
var router = express.Router()
var path = require('path')
var HelloWorld = require('./sample/HelloWorld.js')

router.get('/', function (req, res) {
    res.sendFile(path.join(__dirname, "../../public/main.html"));
})

router.use('/helloworld', HelloWorld)

module.exports = router;

router/index.js에서는 routing을 index 해주는 파일로 요청의 흐름을 정의한다.

HelloWorld variable은 router/sample/HelloWorld.js 모듈을 불러오기 위해 require로 정의된다.

require는 해당 node.js에서 모듈을 불러오기 위한 함수이다.

require는 module.export를 리턴한다.

router 역시 http method와 use method를 정의할 수 있다. 위 index.js에서는 get '/' 일 경우와 /helloworld에 대해 처리하는 라우팅 룰이 정의되어 있다고 볼 수 있다.

public/main.html


main.html은 router/index.js에서 '/'로 유입된 요청에 대한 default page이다.

<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8">
    <title>Main Page</title>
</head>

<body>
    <h1>main page</h1>
    <img src="../images/GodNR.jpg" alt="" width="300px;">
</body>

</html>

router.get('/' ~~)에 의해 라우팅되며, 일반 html을 정의한다. index.js의 sendFile을 통해 호출된다.

잠시 다음 구문에 대해 살펴보자면

router.get('/', function (req, res) {
    res.sendFile(path.join(__dirname, "../../public/main.html"));
})

HTTP GET METHOD로 '/' 요청이 유입되면, __dirname(node가 실행되는 절대 경로 즉, index.js 파일이 위치하는 경로)을 기준으로 ../../public/main.html의 내용을 읽어 클라이언트로 전송한다.

path.join은 ,로 구분되는 parameter를 하나의 route로 결합하는 역할을 한다.

즉 위의 path.join은 D:\workspace\NodeHello\public\main.html이 된다.

router/sample/HelloWorld.js


다음은 HelloWorld Router에 연결된 HelloWorld.js이다.

var express = require('express')
var router = express.Router()

router.get('/', function(req, res){
    res.render('helloSample.ejs');
})

router.post('/', function (req, res) {
    res.render('helloSample.ejs')
})

module.exports = router;

HelloWorld.js는 router/index.js에서 '/helloworld'로 유입된 요청에 대한 Business Logic이 구현되어 있는 API Server, 표출 화면 등과 연계되는 또 다른 router이다.

get '/' 또는 post '/' 요청 시 helloSample.ejs를 랜더링한다.

views/helloSample.ejs


마지막으로 ejs 파일이 하는 views 하위 helloSample.ejs 파일이다.

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>Hello Node EJS</title>
  </head>
  <body>

    <h1>Hello EJS</h1>
  </body>
</html>

EJS는 Embedded JavaScript로 html 템플릿 생성을 위한 모듈이다. JSP와 거의 유사한 형태로 또 다른 언어를 학습할 필요 없이 쉽게 적용이 가능하다. 대체로 EJS는 views 폴더에 위치 시키도록 한다.

다음은 위와 같이 구성된 VSCode 상의 패키지를 확인해 보자.

 node 기동 및 확인 

다음으로 node를 통해 app.js를 기동해 보도록 하자.

기동 방법은 node app.js와 같이 기동하거나 nodemon을 통해 실시간 반영을 위한 모듈을 적용하여 기동할 수 있다.

본 가이드에서는 nodemon으로 기동해 보도록 하자.

기동이 정상적으로 완료되면 다음과 같이 3000번 포트로 호출을 시도해 보자.

위와 같이 HTTP GET /로 요청이 유입될 경우 Default Page인 main.html 호출되었다.

HTTP GET /helloworld를 호출할 경우 위와 같이 HelloSample.ejs가 호출되는 것을 확인할 수 있다.

이를 기반으로 호출된 흐름을 살펴보자면 다음과 같이 도식화 할 수 있다.

Router 처리하는 구조를 종합적으로 살펴보자면,

1) app.js는 ingress를 담당하고, index.js를 지정한다.

2) index.js는 실제 라우팅되는 룰을 정의하여 바인딩한다.

3) context가 '/'일 경우 main.html을 호출하며, '/helloworld'일 경우 HelloWorld.js를 호출한다.

4) HelloWorld.js는 helloSample.ejs를 호출한다.

main.html과 helloSample.ejs는 각각 화면을 표출한다

728x90
반응형