웹 사이트에 접속하기 위한 사이트 주소 정보는 노드에서 URL 객체로 만들 수 있다. url 모듈은 일반 주소 문자열을 URL 객체로 만드는 것을 쉽게 해준다.
메소드 | 설명 |
---|---|
parse() | 주소 문자열을 파싱하여 URL 객체를 만들어 준다. |
format() | URL 객체를 주소 문자열로 변환한다. |
// require() 메소드를 이용해 url모듈을 사용했다.
var url = require('url');
// 주소 문자열 url객체로 만들기
var curURL = url.parse('https://search.naver.com/search.naver?where=nexearch&sm=top_sug.pre&fbm=1&acr=1&acq=steve&qdt=0&ie=utf8&query=steve+jobs');
//url 객체를 주소 문자열로 만들기
var curStr = url.format(curURL);
console.log('%s',curStr);
console.dir(curURL)
결과창을 보면 query속성은 요청 파라미터 정보를 가지고 있다. 웹 서버에서는 클라이언트에서 요청한 요청 파라미터를 받아 처리할 때가 많으므로 이 query 속성에 들어 있는 문자열을 다시 각각의 요청 파라미터로 분리해야한다.
query: 'where=nexearch&sm=top_sug.pre&fbm=1&acr=1&acq=steve&qdt=0&ie=utf8&query=steve+jobs',
querystring 모듈을 이용하면 요청 파라미터를 쉽게 분리할 수 있다.
메소드 | 설명 |
---|---|
parse() | 요청 파라미터 문자열을 파싱하여 요청 파라미터 객체로 만들어준다. |
stringify() | 요청 파라미터 객체를 문자열로 변환 |
노드에는 이벤트를 보내고 받을 수 있도록 EventEmitter라는 것이 만들어져 있습니다.
이벤트는 한쪽에서 다른 쪽으로 어떤 일이 발생했음을 알려주는 것이다. 이때 다른 쪽에서 이 이벤트를 받고 싶다면 Event Listener를 등록할 수있다. 이벤트 리스너는 특정 이벤트가 전달되었을때 그 이벤트를 처리할 수 있도록 만들어 둔것을 말한다.
- 노드의 객체는 EventEmitter를 상속받을 수 있다.
- 상속받은 후에는 EventEmitter 객체의
on()
과emit()
메소드를 사용할 수 있다.
보통은 노드 내부에서 미리 만들어 제공하는 이벤트를 받아 처리하지만, 필요할 때는 직접 이벤트를 만들어 전달할 수 있다.
메소드 | 설명 |
---|---|
on(event,listener) | 지정한 이벤트의 리스너를 추가 |
once(event,listener) | 지정한 이벤트의 리스너를 추가하지만 한 번 실행한 후 자동으로 제거 |
removeListener(event,listener) | 지정한 이벤트에 대한 리스너 제거 |
process.on('exit',function(){
console.log('exit 이벤트 발생');
});
setTimeout(function(){
console.log('2초 후에 시스템 종료 시도');
process.exit();
},2000);
process
객체는 노드에서 언제든지 사용할 수 있는 객체인데, 내부적으로 EventEmitter를 상속받도록 만들어져있다.
같은 이름의 이벤트를 사용하는 경우에 충돌이 생길 수 있으므로 별도의 모듈 파일을 만들고 그 안에서 이벤트를 처리하도록 만드는 것이 좋다.
// calc.js
var util = require('util');
// events모듈을 불러들인 후 EventEmitter객체참조
var EventEmitter = require('events').EventEmitter;
var Calc = function(){
//프로토타입 객체로 this를 사용해 자기자신을 가리킴.
// 그 객체안에 정의된 속성에 접근
var self = this;
this.on('stop',function(){
console.log('Calc에 stop 이벤트 전달');
});
};
// 상속은 util모듈의 inherits()메소드를 이용해서 정의
util.inherits(Calc,EventEmitter);
// new연산자를 이용해 Calc를 만들었을때 add()함수 사용할 수 있음.
Calc.prototype.add = function(a,b){
return a+b;
}
// Calc객체 참조할 수 있도록 지
module.exports = Calc;
module.exports.title = 'calculator';
//test.js
var Calc = require('./calc');
var cal = new Calc();
// 인스턴스 객체의 emit() 메소드 호출해 stop이벤트 전
cal.emit('stop');
console.log(Calc.title+'에 stop 이벤트 전달');
노드의 파일 시스템은 파일을 다루는 기능과 디렉터리를 다루는 기능으로 구성되어 있다. 동기식 IO와 비동기식 IO를 함께 제공한다. 동기식 IO 메소드는 Sync단어를 붙여 구분한다.
// 파일 시스템에 접근하기 위한 fs모듈
var fs=require('fs');
//파일을 동기식 IO로 읽어 들인다.
var data = fs.readFileSync('./package.json','utf8');
//읽어들인 데이터 출력
console.log(data);
// 파일 시스템에 접근하기 위한 fs모듈
var fs=require('fs');
//파일을 비동기식 IO로 읽어 들인다.
//이때 function은 파일을 읽어들이는 작업이 끝났을때 호출한다.
var data = fs.readFile('./package.json','utf8',function(err,data){
//읽어들인 데이터 출력
console.log(data);
});
console.log('프로젝트 폴더 안의 package.json 파일을 읽도록 요청');
비동기식으로 읽어 들이는 방식이 노드에서 더 자주 사용하는 코드이다.
파일을 읽어 들이는 것뿐만 아니라 파일을 쓰는 기능까지 fs모듈에서 정의한다.
메소드 | 설명 |
---|---|
readFile(filename,[encoding],[callback]) | 비동기식 IO로 파일을 읽어들인다. |
readFileSync(filename,[encoding]) | 동기식 IO로 파일을 읽어들인다. |
writeFile(filename,data,encoding='utf8',[callback]) | 비동기식 IO로 파일을 쓴다. |
writeFileSync(filename,data,encoding='utf8') | 동기식 IO로 파일을 쓴다. |
한꺼번에 모든 데이터를 읽거나 쓰지 않고 조금씩 읽거나 쓰는 방식을 사용하는 경우가 있다. 또한 다른 곳에서 받아 온 데이터를 파일에 쓰는 경우가 있다.
메소드 | 설명 |
---|---|
open(path,flags[,model],[,callback]) | 파일을 연다. |
read(fd,buffer,offset,length,position[,callback]) | 지정한 부분의 파일 내용을 읽어들인다. |
write(fd,buffer,offset,length,position[,callback]) | 파일의 지정한 부분에 데이터를 쓴다. |
close(fd[,callback]) | 파일을 닫는다. |
Buffer객체는 바이너리 데이터를 읽고 쓰는 데 사용한다.
// 파일 시스템에 접근하기 위한 fs모듈
var fs=require('fs');
// 파일 열기
fs.open('./output.txt','w',function(err,fd){
//데이터는 필요한 만큼 Buffer객체 안에 슨다.
var buf = new Buffer('안녕\n');
//fd객체로 파일을 구별한다.
fs.write(fd,buf,0,buf.length,null,function(err,written,buffer){
if(err) throw err;
console.log(err,written,buffer);
//파일닫기
fs.close(fd,function(){
console.log('파일 열고 데이터 쓰고 파일 닫기');
})
})
})
|플래그|설명|
|r
|읽기에 사용하는 플래그, 파일이 없으면 예외 발생|
|w
|쓰기에 사용하는 플래그, 파일이 없으면 만들어지고 파일이 있으면 이전 내용을 모두 삭제|
|w+
|읽기와 쓰기에 모두 사용하는 플래그, 파일이 없으면 만들어지고 파일이 있으면 이전 내용을 모두 삭제|
|a+
|읽기와 추가에 모두 사용하는 플래그, 파일이 없으면 만들어지고 파일이 있으면 이전 내용에 새로운 내용추가|
크기를 먼저 지정하면 나머지 공간이 그대로 버퍼에 남아있게 된다. 버퍼인지 아닌지 확인하는 메소드 isBuffer()
, 하나의 버퍼 객체를 다른 버퍼 객체로 복사 메소드 copy()
, 두 개의 버퍼를 하나로 붙여서 새로운 버퍼 객체 만드는 메소드 concat()
사용
스트림은 데이터가 전달되는 통로와 같은 개념이다.
메소드 | 설명 |
---|---|
createReadStream(path[,option]) | 파일을 읽기 위한 스트림 객체를 만든다 |
createWriteStream(path[,option]) | 파일을 쓰기 위한 스트림 객체를 만든다 |
옵션으로는 flags
,encoding
,autoClose
속성이 들어 있는 자바스크립트 객체를 전달할 수 있다.
var fs = require('fs');
var infile = fs.createReadStream('./output.txt',{flags:'r'});
var outfile = fs.createWriteStream('./output2.txt',{flags:'w'});
infile.on('data',function(data){
console.log('읽어 들인 데이터', data);
outfile.write(data);
});
infile.on('end',function(){
console.log('종료');
outfile.end(function(){
console.log('파일쓰기 종료');
});
});
pipe()
메소드는 두 개의 스트림을 붙여주는 역할을 한다.
var fs = require('fs');
var inname = './output.txt';
var outname = './output2.txt';
fs.exists(outname,function(exists){
//파일을 만들기 전에 파일이 이미 존재하면 삭제한다.
if(exists){
fs.unlink(outname, function(err){
if(err) throw err;
console.log('기존 파일 ['+outname+']삭제함');
});
}
var infile = fs.createReadStream(inname,{flags: 'r'});
var outfile = fs.createWriteStream(outname,{flags: 'w'});
//두개의 스트림을 pipe()메소드로 연결해 복사
infile.pipe(outfile);
console.log('파일 복사'+inname +outname);
});
스트림을 서로 연결하는 방법은 웹 서버를 만들고 사용자의 요청을 처리할 대 유용하다.
파일에서 만든 스트림 객체와 웹 서버의 스트림 객체를 pipe()
메소드로 연결할 수 있다. 파일에서 데이터를 읽어 오기 위해 만든 것도 스트림 객체, 데이터를 쓰기 위해 웹서버 클라이언트 쪽에 만든 것도 스트림객체이기 때문에 연결이 가능하다.
var fs = require('fs');
var http = require('http');
var server = http.createServer(function(req,res){
//파일을 읽어 응답 스트림과 pipe로 연결
var instream = fs.createReadStream('./output.txt');
instream.pipe(res);
});
server.listen(7001,'127.0.0.1');
var fs = require('fs');
fs.mkdir('./docs',0666,function(err){
if(err) throw err;
console.log('새로운 docs폴더를 생성');
fs.rmdir('./docs',function(err){
if(err) throw err;
console.log('폴더 삭제');
});
});
프로그램의 크기가 커질수록 로그의 양도 많아지고 로그를 보관했다가 나중에 확인해야하는 경우도 생긴다. 따라서 어떻게 로그를 보관하고 남길지가 중요해진다. winston모듈로 로그를 남기는 법을 알아볼 것이다.
var winston = require('winston'); // 로그 처리 모듈
var winstonDaily = require('winston-daily-rotate-file'); // 로그 일별 처리 모듈
var moment = require('moment'); //시간처리 모듈
function timeStampFormat(){
return moment().format('YYYY-MM-DD HH:mm:ss/SSS ZZ');
};
var logger = new (winston.Logger)({
transports: [
new(winstonDaily)({
name: 'info-file',
filename: './log/server',
datePatter: '_yyyy-MM-dd.log',
colorize: false,
maxsize: 50000000,
maxFiles: 1000,
level: 'info',
showLevel: true,
json: false,
timestamp: timeStampFormat
}),
new(winston.transports.Console)({
name: 'debug-console',
colorize: true,
level: 'debug',
showLevel: true,
json: false,
timestamp: timeStampFormat
})
],
exceptionHandlers:[
new(winstonDaily)({
name: 'exception-file',
filename: './log/exception',
datePatter: '_yyyy-MM-dd.log',
colorize: false,
maxsize: 50000000,
maxFiles: 1000,
level: 'error',
showLevel: true,
json: false,
timestamp: timeStampFormat
}),
new(winston.transports.Console)({
name: 'exception-console',
colorize: true,
level: 'debug',
showLevel: true,
json: false,
timestamp: timeStampFormat
})
]
});
Logger는 로그를 출력하는 객체를 말한다. 로거는 transports라는 속성 값으로 여러 개의 설정 정보를 전달할 수 있다.
이 파일을 실행하기 전에는 몇가지 모듈을 설치해야한다.
% npm install winston --save
% npm install winston-daily-rotate-file --save
% npm install moment --save