Node.js는 Javascript로 개발한다. 아래 코드를 주목해보자.


'use strict';

try {
    null.error;
} catch (e) {
    console.error('catch error: ', e.stack);
}


평상시 에러 잡는 코드를 작성할 때 사용한다. 아무런 의구심도 들지 않는다.
자연스럽게 catch에서 실행될 것이란 걸 알기 때문이다.


아이러니하게도, 비동기 방식으로 개발하게 된다면 상황은 달라진다.
순차적으로 진행되는 코드에 익숙한 게 대부분이다. 들쑥날쑥 동작하는 코드를 보는 순간 당황할 수 있다.


'use strict';

const fs = require('fs');

try {
    fs.readFile('bad', (err) => {
        throw new Error('test error');
    });
} catch (e) {
    console.error('catch error: ', e.stack);
}


비동기 방식으로 파일을 읽고 있으며, 동일하게 에러를 발생시킨다.
catch로 들어오지 못하고, process exit 되는 상황에 놓이게 된다.
callback function은 try ~ catch scope에서 벗어나기 때문에 잡을 수 없다.


'use strict';

const fs = require('fs');

try {
    fs.readFile('bad', (err) => {
        try {
            throw new Error('test error');
        } catch (e) {
            console.error('fs catch error: ', e.stack);
        }
    });
} catch (e) {
    console.error('catch error: ', e.stack);
}


사용하던 대로, 벗어나고 있는 scope에 새로운 try ~ catch를 사용하면 생각대로 진행된다.


전적으로 의존한다면, try ~ catch 천국이 될 것이다.


좀 더 나은 방법으로 고민해보면, node.js의 domain module을 사용하면 된다.
현재도 Deprecated로 명시가 되어있으나, 마땅한 대안이 없어 유지되고 있는 것으로 보인다.


쉽게 보면, global scope, local scope 2가지가 전부다.


'use strict';

const fs = require('fs');
const domain = require('domain');

const fsProtect = domain.create();

fsProtect.on('error', (err) => {
    console.log(err);
    console.error('domain error: ', err.stack);
});

fsProtect.run(() => {
    fs.readFile('bad', (err) => {
        throw new Error('test error');
    });
});


run 함수는, try ~ catch scope와 동일하게 보면 이해가 쉽게 된다.
callback function의 영역도 scope에 포함 되기 때문에, error 이벤트로 진입하게 된다.


{ Error: test error
    at ReadFileContext.fs.readFile [as callback] (error.js:14:15)
    at FSReqWrap.readFileAfterOpen [as oncomplete] (fs.js:365:13)
  domain:
   Domain {
     domain: null,
     _events: { error: [Function] },
     _eventsCount: 1,
     _maxListeners: undefined,
     members: [] },
  domainThrown: true }


error 객체를 자세히 살펴보면, 다른 점이 한가지 있다. run 함수 scope 안에서 에러가 발생하는 경우,
domain 객체가 property로 제공되며, _events에 error 이벤트가 등록되어 있다. 이 점 때문에 error 이벤트를 사전에 등록해줘야만 한다.


간편하게 사용할 수 있는 대표적인 방법이며, 대부분 위와 같은 방식을 사용한다.
한가지 의구심이 드는 부분은, 원하는대로 scope 조절은 불가능 하다는 것이다.


'use strict';

const fs = require('fs');
const domain = require('domain');

const fsProtect = domain.create();

fsProtect.on('error', (err) => {
    console.log(err);
    console.error('domain error: ', err.stack);
});

fs.readFile('bad', fsProtect.intercept((err) => {
    throw new Error('test error');
}));


try ~ catch scope를 생각해보자. 벗어나는 부분만, intercept 함수로 scope 영역을 확대했으며,
동일하게 error 이벤트가 등록되어 있다. scope 조절은 입맛에 맞게 할 수 있다.


일반적으로 프로젝트에 투입되게 되면, web server app, scheduler app을 개발하게 된다.


'use strict';

const http = require('http');
const server = http.createServer();

const domain = require('domain');

server.on('request', (req, res) => {
    const httpProtect = domain.create();

    httpProtect.add(req);
    httpProtect.add(res);

    httpProtect.on('error', (err) => {
        res.statusCode = 500;
        res.setHeader('Content-Type', 'text/plain');
        res.end(`${err.message}\n`);
    });

    httpProtect.run(() => {
        // throw new Error('test error');

        res.statusCode = 200;
        res.setHeader('Content-Type', 'text/plain');
        res.end('Hello World\n');
    });
});

server.listen(3000, '0.0.0.0', () => {
    console.log('server listening');
});


위 코드는 global scope 형태를사용하고 있는데, add 함수는 scope 영역에 객체를 포함한다는 의미이며, 에러가 발생하는 경우, 등록된 error 이벤트로 진입하게 된다.


추가로 고민해야 할 부분이 있는데, 주석을 풀고 요청을 해보자. process exit 될 것이다. error 이벤트로 진입 시 추가적인 에러가 발생했기 때문이다. 보통 error 처리 함수로 정의하고 구현하는데, scope에서 벗어난 영역이므로, 다시 scope를 정의하려고 하는 생각이 일반적이다.


'use strict';

const http = require('http');
const server = http.createServer();

const domain = require('domain');

server.on('request', (req, res) => {
    const httpProtect = domain.create();

    httpProtect.add(req);
    httpProtect.add(res);

    httpProtect.on('error', (err) => {

        const httpErrProtect = domain.create();
        httpErrProtect.add(req);
        httpErrProtect.add(res);

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

        httpErrProtect.run(() => {
            res.statusCode = 500;
            res.setHeader('Content-Type', 'text/plain');
            res.end(`${err.message}\n`);
        });
    });

    httpProtect.run(() => {
        throw new Error('test error');

        res.statusCode = 200;
        res.setHeader('Content-Type', 'text/plain');
        res.end('Hello World\n');
    });
});

server.listen(3000, '0.0.0.0', () => {
    console.log('server listening');
});


별로 문제가 없어 보이긴 한다. scope는 중첩되는 순간, 새로 선언한 scope로 error 이벤트는 등록된다. 상위 scope의 error 이벤트는 동작하지 않는다. run 함수 중첩사용은 시나리오를 예측해서 작성해야만, 대응이 수월할 것이며, 그렇지 않은 경우, error 이벤트의 호출 시점을 예측 할 수 없다.


'Nodejs' 카테고리의 다른 글

Node.js Package 취약점 분석하기  (0) 2017.08.16
Node.js 설치하기  (0) 2017.03.26
Node.js certificate has expired Error 해결하기  (0) 2016.06.17
Node.js Callback에 관한 고찰  (0) 2016.05.30
Node.js v6 버전 업그레이드 후기  (0) 2016.05.29

신뢰하지 않는 HOST로 판단하면, certificate has expired 에러가 발생한다. 테스트서버 구축 시 Openssl로 인증서를 생성해서 사용하기도 하는데 대부분 이런 경우이다. Node.js는 아래와 같이 환경변수를 지정하면 HOST를 판단하지 않는다.


process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0';


'Nodejs' 카테고리의 다른 글

Node.js Error 처리방법  (0) 2017.05.18
Node.js 설치하기  (0) 2017.03.26
Node.js Callback에 관한 고찰  (0) 2016.05.30
Node.js v6 버전 업그레이드 후기  (0) 2016.05.29
NPMv3 사용하기  (0) 2016.04.04

Node.js는 ES6을 지원하고 있다. 고질적인 자바스크립트의 문제점을 보완하는 문법이 제공된다.


무턱대고 사용하다가는 큰 코 다칠 수 있다. 버전 별로 지원되는 기능이 차이가 있기 때문이다. 아래 링크는 지원되는 ES6의 목록이다. Server/runtimes 부분을 참고하자.


http://kangax.github.io/compat-table/es6/



Node.js는 아래와 같은 기능을 기본으로 제공하고 있다.



전체적으로 사용하기에는 시기상조이고, 개인적으로 현재 사용할만한 기능은 자바스크립트에서 항상 문제가 되어왔던 Scope 를 좀더 엄격하게 제한을 두는 문법인 Block scoping, 그리고 Connections 정도라고 생각한다.


참고 사이트


Node.js 프로젝트가 마침표에 가까워질 수록 프로세스를 어떻게 관리해야 할지 고민한다. 요즘은 Node.js Domain API에 완전히 당해서 넋이 나가 있었다.


PM2 로 App 을 시작 할 때 Debug Log를 감시하고 싶을 때가 있다. 아이러니하게도 node debug로 사용된 로그는 stderr 로 출력된다.



stdout 으로 출력하기 위해서는 환경변수를 추가해야 한다.


DEBUG_FD=1


아래는 pm2 설정 JSON 이다. 취향에 따라서 직접 명령으로 실행해도 무관 하다.


  • pm2-test.json
{
    "apps": [
        {
            "name"             : "test-app",
            "script"           : "./test.js",
            "error_file"       : "./logs/app/test-app.stderr.log",
            "out_file"         : "./logs/app/test-app.stdout.log",
            "pid_file"         : "./pids/test-app.pid",
            "instances"        : 0,
            "min_uptime"       : "1000s",
            "max_restarts"     : 15,
            "watch"            : false,
            "ignore_watch"     : ["[\\/\\\\]\\./", "node_modules"],
            "merge_logs"       : true,
            "exec_interpreter" : "node",
            "exec_mode"        : "cluster_mode",
            "autorestart"      : false,
            "vizion"           : false,
            "env"              : {
                "NODE_ENV"     : "development",
                "DEBUG"        : "*",
                "DEBUG_FD"     : 1
            }
        }
    ]
}


명령어를 실행 시 node debug로 사용된 로그는 stdout 으로 출력된다.


pm2 start pm2-test.json



정상적으로 출력 되는 것을 확인 할 수 있다.


'Nodejs' 카테고리의 다른 글

NPMv3 사용하기  (0) 2016.04.04
Node.js와 ECMAScript 2015 (ES6)  (0) 2016.01.04
Node.js NPM Previous Version 설치 하기  (0) 2015.12.08
play.node(2015) 후기  (0) 2015.11.13
Nodejs Express 4.x File Upload 설정 하기  (0) 2015.02.10

Node.js release - https://nodejs.org/en/download/releases/


위 링크는 node.js release 내역이다. windows 환경에서 Node.js v4.x.x, v5.x.x를 번갈아 설치 하다 보면, npm 버전이 3.x.x으로 고정되는 현상이 발생한다. 처음에는 방법을 몰라서 몇 번이고 재설치를 해보았지만, 바보 같은 시도였다. 초심으로 돌아가서 생각해보니 npm 으로 재설치 하면 될까 하는 방법이 떠올랐다.


$ npm -v
3.3.10

$ npm install npm@2.14.7 -g

$ npm -v
2.14.7


npm install {app}@{version}


  • app: 설치 할 앱
  • version: 설치 할 버전

위와 같이 설치 하면, node.js 재 설치 없이, 원하는 버전을 설치 할수있다.




상기 내용에 대한 저작권은 play.node 에 있습니다.


play.node(2015) 후기입니다. 좋은 경험을 할 수 있게 기회를 주신 회사에 감사드립니다.

1. Node.js LTS/Stable





Node.js 는 초창기에 v1.0 이 과연 언제 나올까 기다리는 게 큰 이슈였습니다. 불미스럽게도 node.js 를 fork 로 시작한 io.js 가 나오게 되고 나뉘어 가는 행보를 보였으나, 결국 통합되어 v4.0.0 이 나오게 됩니다. 


기존에는 stable, unstable 정책으로 관리 되었으나, 이번에 새롭게 변경되었습니다.


LTS는 짝수 버전에 해당하며, 안정화, 호환성에 초점을 맞춘 버전이고, stable는 새로운 기능이 활발하게 개발되는 버전입니다.


위 그림은 해당 내용에 대한 버전 일정 이며, 기업에서는 미리 버전 업데이트 일정을 정해서 대비할 수 있습니다.


Node.js 소식은 http://nodejs.github.io/nodejs-ko/ 에서 번역본을 볼 수 있습니다. 번역 까지는 최소 2주 정도 걸린다고 합니다.


2. Node.js Module - (NodeSource/Tim Oxley)


Javascript로 작성되는 프레임워크는 수명이 짧다고 합니다. 해당 언어로 구성된 Node.js 생태계는 격동하는 모습을 보여주고 있고, 프레임워크에 의존하게 되면 새로운 버전이 나왔을 때 맞추어 갈 수 없는 상황이 나오기도 합니다. 예를 들어 C/C++ 로 작성된 모듈이 버전 업데이트를 했을 때 동작하지 않는 경우도 있었다고 합니다. 프레임워크를 도입한다면, 고질적인 문제를 항상 고려해야 합니다.




Node.js 는 프레임워크 보다 상대적으로 모듈화 문화를 적극적으로 지지하고 있고, Node Package Manager(NPM)의 total packages는 공식 홈페이지 2015/11/13 기준 204,841 개입니다.



각 언어의 설치 패키지 pip, gem, maven 등을 합친 수보다 많다고 합니다. 수가 많은 만큼 사용되지 않는 라이브러리도 많으므로, 선점 할때, commit 날짜, 다운로드 수, 버전에 대한 정보는 확인합니다.


실제 애플리케이션을 개발할 때는 라이브러리 개발과 다소 차이가 있다고 합니다. 라이브러리는 단순하면서 사용하기 편해야 합니다. 애플리케이션은 고객의 비지니스를 만족해야 합니다. 개발할 때 자신도 모르게 복잡성 안에 함몰된 있는 모습을 발견합니다. 발표자는 Over Engineering 이라고 표현합니다. 무리한 요구사항이 들어와서 이를 적용해야 하는 데, flat 한 구조, 설계가 된 구조 애플리케이션이 있다고 가정하면, 후자가 훨씬 비용이 많이 들어가게 됩니다. 무리한 설계는 안 하는 좋습니다.


Javascript는 문제가 발생했을 때 해결을 쉽고 빠르게 할 수 있다는 장점이 있습니다. 하지만 끝나지 않는 숙제가 있습니다. 중첩 Callback, 비동기 코드이기 때문에 결과 예측이 쉽지 않습니다. 발표자는 수직적인 구조 사용을 자제하고, flat 한 구조를 권장하고 있습니다.


모듈화를 할수록 Local 복잡도는 감소하는 대신 Global 복잡도는 증가합니다. 최대한 단순하게 개발하고 지나친 모듈화는 피해야 합니다.


3. Node Package Manager [NPM V2 -> NPM V3] - (npm inc/Kat Marchan)




Package Magager 의 Node.js 버전입니다. 흔히 많이 알고 있는 pip, gem, maven과 비슷합니다. 앞에 Node를 붙여 약자로 NPM 이 됩니다.


불편한 점, 버그는 github, twitter 로 개발자들이 문의합니다. NPM V2 중 제일 많았던 문의는 dependence tree입니다. “npm install package” 명령어로 설치를 진행합니다. 각 패키지별 dependence 도 존재 하는 데, 각각 관리를 하므로 중복되는 package가 많고, 규모가 작은 애플리케이션이면 무시할 수 있는 수준이지만, 규모가 커진 경우 애플리케이션 용량이 큽니다. NPM V3 에서는 기능 개선을 하여 각 패키지 dependence 의 중복을 제거하여 기존에는 하위에 하위 폴더로 가는 구조였다면, 같은 선상에서 package가 설치됩니다. 중복을 제거하는 대신 안정화 된 버전의 패키지가 설치되어야 하므로 버전 규칙에 대해 강조 하였습니다.


설치 시 진행 상황을 알고 싶어하는 요청이 있어 NPM V3 에서는 설치 시 Progress Bar를 지원합니다.




npm 다운로드 유저중 42%는 윈도우 개발자이기 때문에 지원을 아까지 않는다고 합니다.


NPM V3 은 Node.js v5.0.0 이상부터 지원합니다.


4. Callback Hell


동기 방식은 차례로 진행되지만, 비동기 방식은 동시에 실행이 되기 때문에 끝났다는 신호를 줘야 합니다. 그 신호가 일명 Callback입니다.


비동기 방식을 동기 방식처럼 개발하기 위해 많은 노력이 있었습니다.


이를 극복하는 라이브러리에 대한 소개입니다.


async

  • 순차 혹은 병렬 실행 지원
  • 어지간한 경우에 쓸만 합니다.

promise

  • ES6 표준에 포함
  • async와 비슷하나 좀 더 깔끔한 코드
  • 병렬 실행이 가능합니다.
  • 예외 처리가 역시 쉽습니다.

출처



Express 가 4.x 이 되면서 Connect 라이브러리를 사용하지 않는다. 프로젝트 생성시에도 body-parser, cookie-parser 를 추가로 설치 해줘야 한다.


파일 업로드 하는 부분에 있어서도 별도의 미들웨어를 사용해야 한다. 간단하게 사용할 수 있는 Multer 를 소개 한다.



설치 시 --save 옵션을 사용하게 되면 package.json 에 추가되어 다른 환경에 설치 시 npm install -d 로 일괄 설치 할 수 있다.


$ npm install multer --save


app.js 에 미들웨어 선언을 하자.


var app = express()
app.use(multer({ dest: './uploads/'}))


파일 업로드 시 아래의 객체에서 확인이 가능 하다.


console.log(req.body)
console.log(req.files)


자세한 내용은 github 를 참조 하도록 하자.


불과 몇 개월 사이에 Node 설치 방법이 참 편리해 졌다.


Nodejs 설치 하기 - http://blog.whitelife.co.kr/85


직접 의존성 라이브러리, Nodejs 를 수동으로 설치 했다. 자세한 글은 위 주소를 참고하자. 금주에 설치 할 일이 있어 조언도 받고, 검색도 해보았다.


Node Version Manager - https://github.com/creationix/nvm


  • Install script (Linux 기준)
curl https://raw.githubusercontent.com/creationix/nvm/v0.19.0/install.sh | bash
git clone https://github.com/creationix/nvm.git ~/.nvm && cd ~/.nvm && git checkout `git describe --abbrev=0 --tags`
source ~/.nvm/nvm.sh

  • Usage
nvm install 0.10
nvm use 0.10


정말 간단하다. 위 명령어를 따라 실행 하기만 하면 된다.


+ Recent posts