블로그 이미지
평범하게 살고 싶은 월급쟁이 기술적인 토론 환영합니다.같이 이야기 하고 싶으시면 부담 말고 연락주세요:이메일-bwcho75골뱅이지메일 닷컴. 조대협


Archive»


 
 

빠르게 훝어보는 node.js

#5 - Express 2/2

조대협 (http://bcho.tistory.com

File upload download 처리

Express는 파일 업로드 기능을 제공한다. Express 의 경우, 파일을 tmp directory에 업로드한후, 업로드가 끝나면 이벤트를 주는 형태이다. 그래서, 파일 업로드가 끝나면 파일 저장 디렉토리로 옮겨 줘야 한다. 그러면 간단하게 코드를 살펴보자.

express에서 업로드되는 file stream multipart 형태로 업로드가 된다. multi part request stream을 인식하려면, express세팅에 bodyParser 미들웨어를 사용함을 명시해줘야 한다.

var app = express();

app.use(express.bodyParser());

http://expressjs.com/3x/api.html#req.files

다른 미들웨어도 이 bodyParser() 미들웨어를 사용하기 때문에, 다른 미들웨어 선언전에 앞쪽에 선언을 해줘야 한다.

다음으로 file 업로드를 해줄 HTML 파일을 정의하자

<form action="/upload" method="post" enctype="multipart/form-data">

    <input type="file" name="myfile" />

    <input type="submit" name="upload" />

</form>

HTTP Post 형태로 multipart 형태로 데이터를 보내며, 파일은 “myfile”이라는 폼 이름으로 전송된다. 이를 받는 코드는 아래와 같다.

var fs = require('fs');

 

exports.upload = function(req, res){

    fs.readFile(req.files.myfile.path,function(error,data){

        var destination = __dirname + '\\..\\uploaded\\'+ req.files.myfile.name;

        fs.writeFile(destination,data,function(error){

            if(error){

                console.log(error);

                throw error;

            }else{

                res.redirect('back');

            }

        });

    });

 

};

파일은 req.files.{폼이름}.path에 업로드 된다. 위의 예제는 파일 컴포넌트의 폼명을 “myfile”로 했기 때문에 파일의 경로는 req.files.myfile.path가 되낟. 다음 fs.readFile을 이용해서 업로드된 파일이 tmp 디렉토리에 모두 업로드가 되면 destination 디렉토리로 복사해주는 예제이다.

tmp 디렉토리의 경우 bodyParser 미들웨어 적용시 적용할 수 있다.

조금 더 효율적인 코드를 구성해보면, 파일을 tmp 디렉토리에 써지지는 것을 바로 읽어서 write destination에 쓸 수 있도록 Stream을 이용할 수 있다. tmp에서 읽어서 destination 디렉토리에 쓰는 것은 위의 예제와 똑같지만, 나중에 설명하겠지만 Stream을 사용하면, 파일을 읽을 때, 쓸 수 있는 만큼만 (버퍼크기만큼만) 읽은 후 쓰기 때문에, 훨씬 효율적인 IO를 할 수 있다.

exports.uploadstream = function(req, res){

    var destination = __dirname + '\\..\\uploaded\\'+ req.files.myfile.name;

    var ws =  fs.createWriteStream(destination);

    fs.createReadStream(req.files.myfile.path).pipe(ws);

    res.redirect('back');

};

아쉬운 점은 Express의 특성상 바로 destination 디렉토리에 write하는 것은 안되고, tmp 디렉토리를 거쳐서 write해야 한다.


JSON REST API

Express JSON 기반의 REST API 구현도 지원하는데, Spring/Java를 알고 있는 개발자라면, 아주 짜증이 날(?) 정도로 express를 이용한 REST API 구현은 매우 간단하다. 설명은 생략하고 먼저 코드부터 보자

app.use(express.json());

app.post('/rest',function(request,response){

    request.accepts('application/json');

 

    // input message handling

    json = request.body;

    console.log('name is :'+json.name);

    console.log('address is :'+json.address);

 

    // output message

    response.json({result:'success'});

 

});

위의 코드는

{

   "name":"Terry",

   "address":"seoul"

}

와 같은 JSON 메시지를 받은 후에, 내용을 파싱하고, { ‘result’:’success’} 라는 리턴을 보내는 코드이다. 먼저 exress.json 미들웨어를 적용하고, request.accept application/json 타입으로 해서 JSON request를 받음을 명시한다.

다음으로는 request.body.{JSON 필드명} 을 사용하면 된다. 위의 예의 경우 JSON 필드명이 name address이기 때문에 그 값에 대한 경로는 body.name body.address가 된다.

Response를 보낼 때에는 위의 예제와 같이 response.json({key:value,…}) 형태로 지정하면 된다. 만약에 HTTP response code를 보내고 싶으면 response,json(HTTP_CODE,{key:value…}) 형태로 지정한다.

예를 들어 response.json(500,{error:’error message’});  형태로 지정할 수 있다.

또한 response.jsonp 메서드를 이용해서 JSONP 를 지원하는데, JSONP는 간단하게 말하면 Cross Site Scripting을 지원할 수 있는 방법이다. 자세한 설명은

http://beebole.com/blog/general/sandbox-your-cross-domain-jsonp-to-improve-mashup-security/

를 참고하기 바란다.


Connect Module pipe line

지금까지 Express의 기능에 대해서 간략하게 살펴보았는데, 에러 처리 방식에 앞서서 Express의 근간이 되는 Connect framework에 대해서 짚고 넘어가고자 한다.

Connect Framework Javascript 를 기반으로 한 웹/서버 개발용 프레임웍이다. Javascript 기반의 서버를 만들기 위해서, 개발되었으며, Ruby Rack Framework을 기반으로 하였다.

Connect에서는 Middleware라는 개념을 사용하는데, reusable한 컴포넌트를 middleware라고 한다. Request, response 파이프라인상에 middle ware를 넣어서 기능을 추가 및 처리 하는 개념인데, Java Servlet Filter Servlet Chaining과 같은 개념과 유사하다고 보면 된다. 아래 그림과 같이 request가 들어와서 서버에서 처리되고 reponse로 나가는 형태라고 할 때,



아래 그림과 같이 처리 과정에 middleware를 추가하여 기능을 처리하도록 할 수 있다.



우리가 지금까지 express를 사용하면서 app.use라고 했던것들이 middleware 모듈을 추가하는 기능이었다.

app.use(express.logger('dev'));

app.use(express.json());

app.use(express.urlencoded());

app.use(express.methodOverride());

app.use(express.cookieParser('your secret here'));

app.use(express.session());

app.use(app.router);

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

 

app.use(function(req,res,next){

   console.log('custom log :'+req.path) ;

   next();

});

 

app.post('/upload', upload.fileupload);

위의 코드를 분석해 보면



와 같은 순서로 middleware가 적용된 것이다.

static 파일의 경우 위에서부터 순차적으로 logger 모듈부터 적용이 되다가 express.static 모듈에서 적용후에, static file response한 다음에 바로 리턴이 된다.

static 파일이 아닌 경우는 모두 아래 함수를 수행하게 되는데

app.use(function(req,res,next){

   console.log('custom log :'+req.path) ;

   next();

});

Middleware로 넘어오는 parameter HTTP request,response 뿐만 아니라 next라는 함수 포인터를 넘겨주는데, middleware를 수행한 다음에 다음 middleware를 실행하기 위한 포인터이다. 위의 예에서는 콘솔에서 로그를 출력한 후에, next()를 호출하여 다음 미들웨어를 호출하도록 하였다.

HTTP/POST /upload request의 경우에는 app.post('/upload', upload.fileupload); 미들웨어에 의해서 처리된다.

이렇게 middleware들은 순차에 의한 chaining 개념을 가지고 있기 때문에, middleware use를 이용해서 불러드릴 경우 순서가 매우 중요함을 알 수 있다.


Error Handling

다음으로 Express에서 에러처리에 대해서 알아보자 Express에서 별도의 에러처리를 하지 않으면, 404의 경우 한줄로 없는 페이지라는 메시지가 나오거나 500 에러의 경우 아래와 같이 에러스택이 바로 표시되어 버린다. (보안상의 이유라도 이런식으로 내부 스택이 나오는 것은 좋지 않다.)



그러면 어떻게 에러 처리를 하는지 알아보도록 하자. 먼저 코드를 보면

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

 

app.get('/error',function(req,res,next){

   // this will make a error

    var err = new Error('custom error');

    err.type = 'my error';

    next(err);

 

});

app.use(function(err,req,res,next){

   console.log(err.type);

   console.log(err.stack);

 

   res.format({

       html: function(){

            res.send(500,'internal server error');

        },

       json:function(){

           res.send(500,{code:err.type,description:'error detail'});

       }

    });

 

});

app.use(function(req,res){

    res.send(404,"I cannot find the page");

} );

 

http.createServer(app).listen(app.get('port'), function(){

  console.log('Express server listening on port ' + app.get('port'));

});

 

먼저 404 에러의 경우 앞에 Connect에서 살펴본 middlewarechaining 개념을 이용하면 된다. 간단하게 다른 middleware에 의해서 처리되지 않은 URL 404로 처리하면 된다. 그래서 middleware를 불러드리는 맨 마지막에 404 에러 처리 로직을 구현하였다.

app.use(function(req,res){

    res.send(404,"I cannot find the page");

} );

 

다음은 500이나 503 같은 에러 처리 방식을 알아보자, 인위적으로 에러를 만들기 위해서 HTTP GET/error 시에 인위적으로 에러를 발생시키는 코드를 구현하였다.

app.get('/error',function(req,res,next){

   // this will make a error

    var err = new Error('custom error');

    err.type = 'my error';

    next(err);

 

});

 

여기서 주의 할점은 node.js의 일반적인 에러 처리 방식 처럼 throw를 통해서 에러를 던지는 것이 아니라 next()를 통해서 에러 메시지를 다음 middleware로 넘기는 형태를 사용한다.next 호출시 인자에 error가 있을 경우 미리 정의된 error handler를 부르게 된다.error handler는 다른 middleware와는 총 4개 인자를 받으며, 다르게 첫번째 인자가 err로 정의 된다.

app.use(function(err,req,res,next){

가 에러 핸들러를 구현한것이며, res.format을 이용하여, 브라우져가 선호하는 포맷 (content/accept에 정의된) 포맷으로 html이나 json으로 메시지를 보내주도록 구현하였다. 예제라서 간단하게 구현했지만, err.type에 에러가 발생할 때 타입을 정해놓으면 error handler에서 이 err.type에 따른 다양한 에러 핸들링 로직을 구현할 수 있고 (예를 들어 Nagios 기반의 모니터링 시스템에 이벤트를 날리거나, IT Admin에게 SMS 메시지를 보내는 것등), 500 error의 경우에는 template을 미리 만들어놓고 잘 디자인된 에러페이지를 출력할 수 있다.

이 밖에도 HTTP Basic Auth를 이용한 인증, 압축 모듈, CSRF (Cross Site Request Forgery) 등을 방어 하는 모듈등 다양한 기능을 지원하는 API 및 모듈이 있다. 자세한 내용은 http://expressjs.com/api.html 을 참고하기 바란다.

오픈소스 시대의 공부하는 방식의 변화

IT 이야기 | 2014.03.01 23:07 | Posted by 조대협


요즘 몸도 안좋고, 일도 바쁘고 집안사도 많아서 그간 블로그 업데이트를 못했습니다

지난 주에는 JCO 발표도 있고, 이런 저런 일이 많았습니다.

오늘은 그간 머릿속에만 담아왔던, 인터넷 시대의 공부하는 변화에 대해서 이야기해보려고 합니다. JCO 컨퍼런스에서 잠깐 언급했었는데, 의외로 반응이, 궁금해하시는 분들이 많더군요.


예전에는 제가 프로그래밍 공부를 시작할때 초창기에만해도 공부할 수 있는 방법이, 책,잡지 그리고 학원 정도의 수준이었습니다. 인터넷 이전 시대 이야기 입니다. 자료를 구하기가 정말어려웠지요. 그러다가 나우콤과 같은 PC 통신 시대가 오고 나서, 제한적이나마 소규모의 정보 교류가 가능해지고, Q&A나 강좌를 구할 수 있게 되었습니다.

그러다가 인터넷이 나오고 나서, 커뮤니티 사이트들이 생기게 되고, 거기를 통해서 강좌도 보고, 인터넷 사이트를 통해서 벤더의 스펙자료나 각종 article 자료도 구하게 되어서 공부할 수 있게 되었습니다.


그러면 현재는?

책은 safarionline에 가입해서, 월정액으로 필요한책은 그때그때 모바일기기나 PC를 통해서 볼 수 있고, 모르는 건 구글링을 하거나 안나오면 stackoverflow에 올리면 됩니다. 강좌는 온라인 강좌가 많고, codeschool과 같은 체계적인 튜토리얼 사이트도 많습니다. 그리고 오픈소스 커미터의 코드가 아니더라도, 일반 개발자들이 공부하려고 올려놓은 코드들이 github에 지천으로 깔렸습니다. 공부를 하기위해서 솔루션 설치를 까다롭게 할 필요 없이 bitnami를 통해서 이미지를 받아서 한번에 설치하고 코딩에 집중하거나, 서버가 없다면 프로모션 쿠폰을 구해서 클라우드 계정이나 mongolab과 같은 Paas 서비스를 사용할 수 도 있습니다. 이제는 노트북이 아니라, 잘하면 크롬북 하나만 있어도 프로그래밍 공부하는데 문제가 없겠더군요.


그러면 제가 공부하는 노하우를 하나 공유해드리면, 

직업 특성상, 현재 기술 트랜드를 잘 파악해야 합니다. 이런 트렌트는 facebook 기술 커뮤니티나 infoq, dzone과 같은 개발 정보 사이트에 가면 주로 올라오는 기술들이 있습니다. node.js,, mongodb, redis 이런 기술들이 유행이지요. 그러면 이 기술들이 정말로 유용한지, 트렌드가 맞는지 확인을해야 하는데, google analytics인가? 에 들어가서 키워드와 유사 기술로 비교 해보면, 이 기술의 현재 인기도를 파악할 수 있고, stack overflow에서 간단하게 검색만 해서 검색 결과 수나, 또는 아마존에서 관련 서적수를 체크해봐도 됩니다. 그리고 이 기술들이 현업에서 많이 쓰이는지를 보려면, monster.com (미국의 jobkorea)나 career 2.0과 같은 구인 사이트에서, 해당 기술로 검색을 해보면, job opening 수가 나옵니다. 

트렌드가 되는 기술과 현재 시장에서 많이 쓰는지 파악이 됩니다.


여기까지 파악하면, 이 기술이 주류인지 아닌지가 판단이 됩니다. 그러면 이 기술 자체를 파악해야 하는데, 빠른 시간내에 파악하려면 먼저

slideshare.net에 들어가면 overview ppt들이 많습니다. 이런 ppt를 5~6개 쭈욱 훝어 봅니다. 그러면 반복되는 목차들이 대략적인 핵심 내용입니다. 그 후에 youtube에 들어가면 강의들이 많습니다. 조회수가 많은 강의를 한두개 정도 들어본 후에, 그 다음 부터는 심화 학습에 들어갑니다.

페이스북 커뮤니티를 통해서 기술에 대해서 의견도 물어보고 장단점도 체크해보고, 그 다음에는 실제로 깔아서 공부합니다. learning path는 이미 slide share에서 잡았기 때문에 그 순서로 공부를 하는데, 해당 기술에 대한 tutorial들이 많습니다. 이런 tutorial 문서를 기반으로 빠르게 기술을 습득한 다음에, 실제 코딩도 해보고 글도 정리해보고 막히면 stackoverflow에가서 물어보기도 합니다.

 범위가 넓은 기술들은 차라리 온라인 강좌 사이트 codeshool, codeacademy 등을 이용합니다. 유료도 있지만 무료도 있습니다.

샘플 코드를 만들어 보고, 코드를 github에도 올려보고, 공부가 되었으면 stackoverflow에 답글을 달 수 있을지 봅니다. (대부분 달기 어렵습니다. 초짜가 달아야 얼마나.. 달겠습니까?) 그래도 이제 질문은 이해가됩니다.


대략 이런 형태로 지식을 습득해 나갑니다.

나름 빠르게 기술을 습득하는 노하우인데, 공유합니다. ;)

더 좋은 공부하는 방법이 있으면 공유해주세요.


예전에 비해서 집에 앉아서 인터넷 연결되는 PC만 있으면 모든 첨단 기술을 공부할 수 있습니다. 예전에는 기술정보에 대한 접근 권한이 차이가 있었기 때문에, 경쟁력에 우위를 점할 수 있었지만, 이제는 누가나 할 수 있기 때문에, 어떤 기술을 얼마나 짧은 시간에 효과적으로 습득할 수 있느냐가 관건인것 같습니다.


마지막으로 덧 붙이자면.. "근데 영어 읽기 쓰기가 되야 합니다. ㅜㅡ "


즐거운 BEA...

사는 이야기 | 2007.11.28 11:49 | Posted by 조대협

난 항상 바쁘다..
말은 바쁘다고는 하지만.. 솔직히 게으른 편이라서 시간을 효율적으로 사용하는가에 대해서는 다소 의문이 있지만..

이번 프로젝트를 끝내고 다음 프로젝트는 Wiki like한 솔루션을 가지고 프로젝트를 하게되었다.
그런데. 헉...!!
이 제품 구조를 대충 뜯어보니 DWR,Spring,JSF,JSON etc 오픈소스로 아주 발라져있네 그려....
오늘 JSF In Action 책도 구입하고, 교육팀에서 JSF 교육 자료도 받아오고..
한참 동안은 또 이 JSF를 파봐야겠다..

근데 어쩌냐?
제품 공부도 해야하고, JSF도 공부해야 하고, 금요일에 발표할 SCA자료도 만들어야 하고..
담달에 xUnit 테스트 기고 준비도 해야 하는데..
-_-
너무 일만 벌리는게 아닌가도 싶네 그려..

그래도 항상 공부할것이 있고, 공부할 수 밖에 없는 환경이 있다는 것이 즐겁다.
좀더 부지런해져야지. -_-

'사는 이야기' 카테고리의 다른 글

육아,출산 강좌..  (0) 2007.12.13
맥사용하시는 분들 의견좀..  (1) 2007.12.12
즐거운 BEA...  (0) 2007.11.28
시간 활용 방법  (4) 2007.10.02
우리 아가 블로그 오픈 했습니다.  (1) 2007.09.28
맛있는 칼국수집  (0) 2007.09.10
TAG bea, 공부