function b64toBlob(b64Data, contentType, sliceSize) {

if( b64Data == "" || b64Data == undefined ) return null;


contentType = contentType || '';

sliceSize = sliceSize || 512;


var byteCharacters = atob(b64Data);

var byteArrays = [];

for (var offset = 0; offset < byteCharacters.length; offset += sliceSize) {

var slice = byteCharacters.slice(offset, offset + sliceSize);

var byteNumbers = new Array(slice.length);

for (var i = 0; i < slice.length; i++) {

    byteNumbers[i] = slice.charCodeAt(i);

}

var byteArray = new Uint8Array(byteNumbers);

byteArrays.push(byteArray);

}

var blob = new Blob(byteArrays, {type: contentType});

return blob;

}

 위의 함수를 사용하여 Base64 형태의 이미지를 Blob 형태로 다시 변경해 준다.


var form = document.getElementById("testForm");


var ImageURL = "data:image/gif;base64,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";

// Split the base64 string in data and contentType

var block = ImageURL.split(";");

// Get the content type of the image

var contentType = block[0].split(":")[1];     // In this case "image/gif"

// get the real base64 content of the file

var realData = block[1].split(",")[1];     // In this case "R0lGODlhPQBEAPeoAJosM...."


// Convert it to a blob to upload

var blob = b64toBlob(realData, contentType);


// Create a FormData and append the file with "image" as parameter name

var formDataToUpload = new FormData(form);

formDataToUpload.append("image", blob);


$.ajax({

    url:"insert.do",

    data: formDataToUpload,    // Add as Data the Previously create formData

    type:"POST",

    contentType:false,

    processData:false,

    cache:false,

    dataType:"json", // Change this according to your response from the server.

    error:function(err){

        console.error(err);

    },

    success:function(data){

        console.log(data);

    },

    complete:function(){

        console.log("Request finished.");

    }

});


출처 : https://ourcodeworld.com/articles/read/322/how-to-convert-a-base64-image-into-a-image-file-and-upload-it-with-an-asynchronous-form-using-jquery

<div class="table-wrap form-table" id="jqueryHtmlTest">

<table class="table table-horizon">

<colgroup>

<col style="width:245px" />

</colgroup>

<tbody>

<tr>

<th>TAB</th>

<td>

jQuer .html<br /><br />테스트

</td>

</tr>

<tr>

<th>버튼</th>

<td>

<button type="button" class="btn" onclick="jqueryTest()">테스트</button>

</td>

</tr>

</tbody>

</table>

</div>

위와 같은 HTML 소스를 jQurery의 .html() 또는 DOM의 InnerHTML로  가져 올경우에 문제점이 있습니다.

<script>

function jqueryTest() {

console.log( $("#jqueryHtmlTest").html() );

}

</script>

이렇게 출력할 경우 결과는

<table class="table table-horizon">

<colgroup>

<col style="width:245px">

</colgroup>

<tbody>

<tr>

<th>TAB</th>

<td>

jQuer .html<br><br>테스트

</td>

</tr>

<tr>

<th>버튼</th>

<td>

<button type="button" class="btn" onclick="jqueryTest()">테스트</button>

</td>

</tr>

</tbody>

</table>

위와 같이 col 이나 br 또는 input 등의 닫힘이 없어 지는 현항이 있습니다.

이 소스를 가지고 PDFWriter을 이용하여 PDF를 만들고자 할 때 오류가 발생합니다.

Invalid nested tag head found, expected closing tag col.

이러한 오류가 발생합니다.


그래서 처리 방법은 new XMLSerializer() 이넘을 이용하는 방법이 있습니다.

<script>

function jqueryTest() {

var oSerializer = new XMLSerializer();

xmlString = oSerializer.serializeToString($("#jqueryHtmlTest")[0]);

console.log( xmlString );

}

</script>

위 소스의 결과는 

<div xmlns="http://www.w3.org/1999/xhtml" class="table-wrap form-table" id="jqueryHtmlTest">

<table class="table table-horizon">

<colgroup>

<col style="width:245px" />

</colgroup>

<tbody>

<tr>

<th>TAB</th>

<td>

jQuer .html<br /><br />테스트

</td>

</tr>

<tr>

<th>버튼</th>

<td>

<button type="button" class="btn" onclick="jqueryTest()">테스트</button>

</td>

</tr>

</tbody>

</table>

</div>

이렇게 출력됩니다.

결과 물을 보면 xmlns="http://www.w3.org/1999/xhtml" 항목이 붙어서 나오게 됩니다.

PDFWriter에서 저 항목이 있으면 생성은 되나 생성된 PDF 파일이 열리지 않는 문제가 있어 저 부분을 삭제 하고 생성하면 정상적으로 생성됩니다.



Restfull을 사용 할 때 method 방식에 put 또는 delete 의 경우 jquery에서는 $.ajax를 사용하여만 하는 번거로움이 있습니다.


Method PUT을 사용할 경우


1
2
3
4
5
6
7
8
9
$.ajax({
    url : "/user",
    type : "PUT",
    data : $("#testForm").serialize(),
    dataType : "text",
    success: function(result) {
        console.log( result );
    }
});




Method DELETE를 사용할 경우


1
2
3
4
5
6
7
$.ajax({
    type : "DELETE",
    dataType : "text",
    success: function(result) {
        console.log( result );
    }
});





위의 소스를 $.post나 $.get 처럼 사용하고자 할 때 다음 예제를 이용하면 됩니다.



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
jQuery.each([ "put""delete" ], function(i, method) {
    jQuery[method] = function(url, data, callback, type) {
        if (jQuery.isFunction(data)) {
            type = type || callback;
            callback = data;
            data = undefined;
        }
 
        return jQuery.ajax({
            url : url,
            type : method,
            dataType : type,
            data : data,
            success : callback
        });
    };
});



사용 :


Method PUT을 사용할 경우


1
2
3
$.put("/user", $("#testForm").serialize(), (result) => {
    console.log( result );
},"text");



Method DELETE를 사용할 경우


1
2
3
$.delete("/user/kamsi76", (result) => {
    console.log( result );
},"text");


Express.js의 라우팅은 URI(경로), HTTP 요청 Method(GET, POST 등)의 특정 엔드포인트에 대한 클라이언트 요청에 응답하는 방법을 결정하는 것을 말합니다.



라우트 Method 설정


라우터의 기본 구조는 다음과 같습니다.


app.method(path, handler)

    • method - HTTP 요청 Method
    • path - 엔드포인트 경로
    • handler - 클라이언트 접속 시 실행 되는 함수


위의 구조를 보듯이 각 메소드 별로 처리 라우터를 지정할 수 있다.


1. GET 방식 호출


1
2
3
app.get('/', (req, res) => {
  res.send('Hello World!');
});



2. POST 방식 호출


1
2
3
app.post('/', (req, res) => {
  res.send('Got a POST request');
});



3. PUT 방식 호출


1
2
3
app.put('/user', (req, res) => {
  res.send('Got a PUT request at /user');
});



4. DELETE 방식 호출


1
2
3
app.delete('/user', (req, res) => {
  res.send('Got a DELETE request at /user');
});



5. 모든 Method 접근 허용


1
2
3
app.all('/', (req, res) => {
  console.log('All Method request ...');
});




라우트 경로 설정


라우트 경로는 문자열 또는 문자열 패턴 그리고 정규식으로 지정할 수 있습니다.



1. 문자열


기본은 위의 예제와 같이


1
2
3
app.get('/', (req, res) => {
  res.send('Hello World!');
});





이렇게 호출 됩니다.


/about 에 접근하자 할 경우에는 다음과 같이 작성을 하면 됩니다.


1
2
3
app.get('/about', (req, res) => {
  res.send('about');
});




2. 문자열 패턴


다음 예제는 경로가 /abcd 또는 /acd 에 접근이 가능하도록 합니다.


1
2
3
app.get('/ab?cd', (req, res) => {
  res.send('ab?cd');
});



다음 예제는 /abcd 또는 /abbbbbbcd 등의 경로에 접근이 가능하도록 합니다. 


1
2
3
app.get('/ab+cd', (req, res) => {
  res.send('ab+cd');
});



다음 예제는 /abcd 또는 /ab123cd 등과 같이 ab와 cd 사이에 어떠한 문자가 와도 접근이 가능하도록 합니다.


1
2
3
app.get('/ab*cd', (req, res) => {
  res.send('ab*cd');
});



3. 정규식


다음은 예제는 a가 포함된 모든 경로에 접근하도록 합니다.


1
2
3
app.get(/a/, (req, res) => {
  res.send('/a/');
});


다음 예제는 fly로 끝나는 경로에 접근이 가능하도록 합니다.


1
2
3
app.get(/.*fly$/, (req, res) => {
  res.send('/.*fly$/');
});





라우트 핸들러(Callback 함수)


라우팅 핸들러는 하나 이상으로 설정이 가능합니다.


1
2
3
app.get('/example', (req, res) => {
  res.send('Hello from A!');
});



위와 같이 라우터 핸들러를 하나만 가지는걸 기본으로 하지만 다음과 같이 1개 이상의 라우터 핸들러를 처리할 수도 있습니다. 그러기 위해서는 next() 를 반드시 호출해 줘야 합니다. 


1
2
3
4
5
6
app.get('/example'function (req, res, next) {
  console.log('the response will be sent by the next function ...');
  next();
}, function (req, res) {
  res.send('Hello from B!');
});


위와 같이 next를 사용하면 다음 핸들러를 호출할 수 있습니다.


또한 함수들을 만들어서 배열 형태로 라우트 처리를 할 수 있습니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var cb0 = function (req, res, next) {
  console.log('CB0');
  next();
}
 
var cb1 = function (req, res, next) {
  console.log('CB1');
  next();
}
 
var cb2 = function (req, res) {
  res.send('Hello from C!');
}
 
app.get('/example', [cb0, cb1, cb2]);



Console 결과는 다음과 같습니다.


1
2
3
CB0
CB1
Hello from C!






app.route()


라우트 경로에 대한 체인이 가능하도록 작성이 가능합니다.


정의된 체인 라우트 핸들러는 다음과 같이 사용합니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
app.route("/chain")
    .all((req, res, next) => {
        console.log('Time: 'Date.now());
        next();
    })
    .get((req, res) => {
        console.log("GET call~");
        res.send("LIST BOOK~~~~");
    })
    .post((req, res) => {
        console.log("POST call~");
        res.send("INSERT BOOK~~~~");
    })
    .put((req, res) => {
        console.log("PUT call~");
        res.send("UPDATE BOOK~~~~");
    })
    .delete((req, res) => {
        console.log("DELETE call~");
        res.send("DELETE BOOK~~~~");
    });





express.Router


express.Router을 사용하면 모듈식 라우트 핸들러를 작성할 수 있습니다.


express.Router로 작성은 Java 웹프로그램으로 따졌을 때 Controller과 비슷하다(??) 라고 할 수 있을 듯하네요.


위의 chain route를 기준으로 모듈 작성은 다음과 같이 합니다.


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
const express = require("express");
const router = express.Router();
 
router.route("/")
    .all((req, res, next) => {
        console.log('Time: 'Date.now());
        next();
    })
    .get((req, res) => {
        console.log("GET call~");
        res.send("LIST BOOK~~~~");
    })
    .post((req, res) => {
        console.log("POST call~");
        res.send("INSERT BOOK~~~~");
    })
    .put((req, res) => {
        console.log("PUT call~");
        res.send("UPDATE BOOK~~~~");
    })
    .delete((req, res) => {
        console.log("DELETE call~");
        res.send("DELETE BOOK~~~~");
    });
 
module.exports = router;



이렇게 모듈을 생성을 하고 app메서는 다음과 같이 로딩합니다.


1
2
3
4
5
6
7
8
9
10
const express = require("express");
const app = express();
 
const chain = require("./chain");
 
app.use("/chain", chain);
 
app.listen(3000, () => {
    console.log( "Express Server port 3000");
});


그리고 최종적으로 브라우저에서 확인을 해보면 결과를 확인할 수 있습니다.



'JavaScript > NodeJS' 카테고리의 다른 글

[NodeJS] Express.js - Hello World!!!  (0) 2017.12.05
[NodeJS] Express.js 시작  (0) 2017.12.05
[NodeJS] 서버 만들기(HTTP Server) - 2  (0) 2017.11.28
[NodeJS] 서버 만들기(HTTP Server) - 1  (0) 2017.11.27
[NodeJS] File System  (0) 2017.11.16

Express.js를 사용하기 위하여서는 express 모듈을 로딩해야 합니다.


 const express = require("express");


이후 어플리케이션을 생성합니다.


const app = express();


app.get() 함수를 이용하여 라우팅 정의를 합니다.


app.get("/", (req, res) => {

res.send("Hello world!!!");

});


마지막으로 app.listen(port[, callback]) 함수를 통해 포트를 지정해 줍니다.


app.listen(3000, ()=> {

console.log( "Express Test Server started on port 3000" );

});



전체 소스는 다음과 같습니다.


1
2
3
4
5
6
7
8
9
10
const express = require("express");
const app = express();
 
app.get("/", (req, res) => {
    res.send( "Hello world!!" );
});
 
const server = app.listen(3000, () => {
    console.log( "Express Test Server started on port 3000" );
});



server.js 파일을 실행하면 console 창에 Express Test Server started on port 3000 출력이 됩니다.


또한 브라우저를 열어서 localhost:3000 을 주소창에 입력하고 실행하면 화면에 Hello world!!!가 출력되는 것을 확인할 수 있습니다.


'JavaScript > NodeJS' 카테고리의 다른 글

[NodeJS] Express.js - 라우팅  (0) 2017.12.05
[NodeJS] Express.js 시작  (0) 2017.12.05
[NodeJS] 서버 만들기(HTTP Server) - 2  (0) 2017.11.28
[NodeJS] 서버 만들기(HTTP Server) - 1  (0) 2017.11.27
[NodeJS] File System  (0) 2017.11.16

Express.js는 

    • HTTP 요청 본문 파싱.
    • 쿠키 파싱
    • 세션관리
    • 라우팅구성
    • 데이터 타입을 토대로 한 적절한 응답 헤더 설정
등의 복잡한 문제를 해결함고 동시에 웹의 MVC 형태의 구조를 제공합니다.


Express.js 설치 방법은 두가지가 있습니다.


1. CMD 명령을 이용한 설치


> npm install -g express 


또는 


> npm install -g express@4.16.2 와 같이 버전을 명시 해주도록 합니다.(권장)



2. package.json 파일을 생성하여 npm으로 Dependency(의존패키지)를 이용한 설치


프로젝트 폴더를 이동하여 직접 package.json을 타이핑하여 만들거나 > npm init 명령을 실행하여 만들수 있습니다.


아래의 이미지는 > npm init 를 실행했을 때 화면입니다.



> npm init 를 실행하고 나면 package.json 파일이 생성되어 있는 것을 확인 할 수 있습니다.


package.json의 내용은 다음과 같습니다.


{

  "name": "nodejstest",

  "version": "1.0.0",

  "description": "",

  "main": "index.js",

  "scripts": {

    "test": "echo \"Error: no test specified\" && exit 1"

  },

  "author": "",

  "license": "ISC"

}


해당 package.json 파일에 의존패키지 리스트 정보를 입력합니다.

{

  "name": "nodejstest",

  "version": "1.0.0",

  "description": "",

  "main": "index.js",

  "scripts": {

    "test": "echo \"Error: no test specified\" && exit 1"

  },

  "author": "",

  "license": "ISC",

  "dependencies": {

    "express": "~4.16.2",

    "ejs": "~2.5.7"

  }

}


이후 cmd 창에 > npm install 을 실행하면 설치가 완료 됩니다.


그러면 node_modules 폴더가 생성되고 express를 설치하기 위한 항목들이 설치되어 있는 것을 확인할 수 있습니다.



하지만, 난 eclipse를 사용하기 때문에..


그냥 Node.js Express Project를 생성하여 사용합니다..ㅡㅡ;;

'JavaScript > NodeJS' 카테고리의 다른 글

[NodeJS] Express.js - 라우팅  (0) 2017.12.05
[NodeJS] Express.js - Hello World!!!  (0) 2017.12.05
[NodeJS] 서버 만들기(HTTP Server) - 2  (0) 2017.11.28
[NodeJS] 서버 만들기(HTTP Server) - 1  (0) 2017.11.27
[NodeJS] File System  (0) 2017.11.16

이번에는 작성한 HTML을 서버를 통해 화면에 출력해 주도록 합니다.


index.html 생성합니다.


<!DOCTYPE html>

<html>

<head>

<meta charset="UTF-8">

<title>NodeJS Test</title>

</head>

<body>

Hello world!!!

</body>

</html>


그리고 이전 server.js를 수정합니다.


const http = require("http");

const fs = require("fs");

const url = require("url");


http.createServer( (request, response) => {


const path = url.parse(request.url, true).pathname;

if( path === "/" ) {

response.writeHead(200, { "Content-type" : "text/html"} );

fs.readFile(__dirname + "/views/index.html", "utf8", (err, data) => {

if( err ) {

return console.error(err);

}


response.end( data, "utf8" );

});

} else {

response.writeHead(404, { "Content-type" : "text/html; charset=utf-8"} );

response.end("해당하는 URL이 존재하지 않습니다.", "utf8" );

}


}).listen(8080, () => {

console.log( "Server Start. localhost:8080" );

});


파일을 읽어 오기 위해서 File System 모듈의 readFile()을 사용하였습니다.

또한 요청한 경로를 알기 위하여 url 모듈을 사용하였습니다.


또한 response.writeHead(stateCode[, statusMessage][, headers] )를 사용하였습니다.

response.writeHead 메소드는 response.setHeader과 같이 header을 설정하는 메소드 입니다.


결과 적으로 header을 설정하고 response.end( data )를 통하여 응답 Data를 전송하게 됩니다.


이후 브라우저에 http://localhost:8080 라고 입력을 하면 화면에 Hello world!! 가 출력되는 것을 확인할 수 있을 것입니다.



'JavaScript > NodeJS' 카테고리의 다른 글

[NodeJS] Express.js - Hello World!!!  (0) 2017.12.05
[NodeJS] Express.js 시작  (0) 2017.12.05
[NodeJS] 서버 만들기(HTTP Server) - 1  (0) 2017.11.27
[NodeJS] File System  (0) 2017.11.16
[NodeJS] Path  (0) 2017.11.13

HTTP Server를 만들기 위하여 먼서 http 모듈을 로딩한다.


const http = require("http");


Server 기본 형태는 다음과 같다.


http.createServer( (request, response) => {

console.log( "Server Request....!!" );

}).listen(8080, () => {

console.log( "Server Start. localhost:8080" );

});


작성후 nodejs를 실행하고 브라우저에서 http://localhost:8080을 호출하면 


console 창에 

Server Start. localhost:8080

Server Request....!!

이와 같이 출력되는 것을 확인 할 수 있을 것이다.


하지만 브라우저에는 아무것도 찍히지 않을 것이다.


http 모듈의 createServer(callback)를 이용하여 Server를 생성하고 insten(port[, callback]) 를 통해 포트를 지정한다.


createServer 함수의 callback에는 request와 response를 가지고 있다.


request는 요청을, response는 응답을 담당한다.


request와 response는 별도의 설명은 하지 않겠다.


그럼 Server가 정상적으로 요청을 받고 응답하여 주도록 수정해 보도록 하겠다.


http.createServer( (request, response) => {


request

.on( "error", (err) => {

console.error(err);

})

.on( "data", (data) => {

console.log( data );

})

.on( "end", () => {


response

.on( "error", (err) => {

console.error(err);

});


response.statusCode = 200;

response.setHeader( "Content-Type", "text/plain" );

response.write( "Hello world!!" );

response.end( "Complate!!" );

});


}).listen(8080);


request나 response는 둘다 Event emitter를 사용한다.


request는 

에러에 대한 이벤트를 발생하는 error,

Data를 처리하는 data,

Data 처리가 완료되었다는 end

로 구분을 한다.


request의 요청이 끝나면 당연히 response 처리를 해야 한다.


response는 Error에 대한 이벤트를 발생하는 error Emitter를 사용한다.

이후에 성공적으로 전송했다고 하는 state code 200을 설정하고

response의 header를 설정하여 준다.


이 소스에서는 단순 text이기 때문에 text/plain으로 처리하였다.


그리고 마지막으로 response.write( data ) 와 response.end( [data] )를 통해 응답에 대한 정보를 보내준다.


write와 end는 동일한 역할을 하지만 최종적으로는 반드시 end를 사용하여 response가 종료되었다고 알려줘야한다.


이후 다시 브라우저를 통하여 확인하면


Hello world!!

Complate!!


라고 결과가 출력되는 될것이다.


'JavaScript > NodeJS' 카테고리의 다른 글

[NodeJS] Express.js 시작  (0) 2017.12.05
[NodeJS] 서버 만들기(HTTP Server) - 2  (0) 2017.11.28
[NodeJS] File System  (0) 2017.11.16
[NodeJS] Path  (0) 2017.11.13
[NodeJS] Event 활용 - 연결 및 제거  (0) 2017.11.10

지금까지 javascript를 사용하면서 모든 변수 선언에 var만 사용하였었는데...


그래도 아무 이상이 없었었는데...


올만에 문서들을 보다가 let와 const가 보여서 찾아 봤더니... 이런...


내가 잘 못하고 있었구나 라는 생각이 똭~~~~~~


ES6으로 넘어오면서 생긴 let와 const선언 방법이 생긴것이다.



우선 차이를 하나하나 설명을 해 보면 다음과 같다.


var foo = "bar1";

var foo = "bar2";


이와 같이 동일 변수명으로 설정을 할 경우 최종적으로 출력되는 것은 bar2 가 출력 될 것입니다.

당연히 오류가 발생하지 않겠지요.


하지만 let이나 const를 사용할 경우를 보면


let foo = "bar1";

let foo = "bar2";


이와 같이 실행하면?


let foo = "bar2";

      ^


SyntaxError: Identifier 'foo' has already been declared

    at createScript (vm.js:80:10)

    at Object.runInThisContext (vm.js:139:10)

    at Module._compile (module.js:599:28)


먼저 선언되어 있다고 중복되었다고 오류가 발생하지요~


프로그램상으로 보면 이것이 바람직한 것이지 않을까요?


계속 해서 


console.log(foo);


라고 변수 선언없이 호출을 하였을 경우


console.log(foo);

            ^


ReferenceError: foo is not defined


이러한 오류가 발생합니다.


그런데 


console.log(foo);

var foo;


이렇게 하면 어떻게 출력이 될까요?


콘솔에는 undefined 이 뜨고 오류가 발생하지 않습니다.


이런 현상을 호이스[각주:1]트 된다고 하는데 이것은 다음에 설명을 하도록 하겠습니다.


다시 위의 코드를 let이나 const로 바꾸면


console.log( foo );

let foo;


console.log(foo);

            ^


ReferenceError: foo is not defined


결과가 나오게 됩니다.



또한 let와 const는 block-scope라고 합니다. 이 말인 즉슨 block로 감싸져 있는 내에서만 허용된다는 것입니다.


다시 예를 들어 var로 선언했을 때와 let로 선언했을 때의 결과를 보면 다음과 같습니다..


var foo = "bar1";

console.log( foo );        // bar1


{

var foo = "bar2";

console.log( foo );    // bar2

};


console.log( foo );        // bar2

let foo = "bar1";

console.log( foo );        // bar1


{

let foo = "bar2";

console.log( foo );    // bar2

};


console.log( foo );        // bar1


var 와 let의 차이점이 보이나요??


다음 예제를 다시 보면


let foo = "bar1";

console.log( foo );        // bar1


{

console.log( foo );    // bar1

foo = "bar2";

console.log( foo );    // bar2

};


console.log( foo );        // bar2

let foo = "bar1";

console.log( foo );        // bar1


{

console.log( foo );    // ReferenceError: foo is not defined

let foo = "bar2";

};


console.log( foo );



{} 밖에 let로 변수를 선언하고 {} 안에서 선언을 하지 않은 경우는 {} 밖의 변수 값을 따라가게 됩니다.


하지만 {}안에서 변수가 다시 선언될 경우 ReferenceError: foo is not defined 를 발생시키게 됩니다.



그럼 let과 const의 차이점은 무엇일까?


결론 적으로 이야기를 하자면 let은 변수선언이며 const는 이름에서 유추 되듯이 상수 선언이 됩니다.


const foo = "bar1";

foo = "bar2";


이렇게 선언 후 변수값을 다시 변경하고자 할 경우 


foo = "bar2";

    ^


TypeError: Assignment to constant variable.


이와 같은 오류가 발생합니다.


하지만 참조형의 경우 경우는 const를 사용하라고 하네요...


배열(array), 객체(object), 함수(function)같은 참조형은 const를 사용하는게 바람직하다고 합니다...


const로 선언하더라도 참조형은 조작이 가능합니다.


const foo = [0, 1];

const bar = foo;


foo.push(2);

bar[0] = 10;


console.log( foo, bar );    //[ 10, 1, 2 ] [ 10, 1, 2 ]


이런식으로~


확실한 차이점은 있네요.. 그리고 지금까지 var만 썼었지만 이제는 var 보다는 let이나 const를 사용하도록 하여야 겠네요~





  1. 후선언된 변수나, 함수들이 해당 Scope에서 최상위에 위치하는걸 뜻한다. [본문으로]

파일 시스템은 fs 모듈을 로딩함으로 사용할 수 있다.


var fs = require("fs");


node.js는 유닉스 개발자가 개발한걸로 알려졌서 그런지 모듈의 대부분 메소드가 유닉스의 명령어와 비슷한 듯 하다.


수 많은 메소드들이 있지만 주로 사용하게 될 몇 가지만 확인해 보도록 한다.


나머지는 API를 참고 하며 진행해야 할 듯...ㅡㅡ;;


모든 파일 시스템은 동기와 비동기를 지원한다.


예를 들어 


fs.readFile("D:\\temp\\out.log", function(err, data) { ... } );


는 비동기 이지만


fs.readFileSync("D:\\temp\\out.log");


는 동기 형식으로 거의 대부분의 메소드에서 Sync를 붙여 동기식으로 구현이 가능하다.


하지만 나는 비동기 형식만 여기에 작성할 것이다.



1. fs.stat(file, callback);


파일의 상태 정보를 확인한다.


callback :

err<Error> : 에러 정보

stats<Stats> : 상태 정보 


fs.stat("D:\\temp\\out.log", (err, stats) => {


if( err ) { throw err; }


console.log( stats );             // 파일 정보

console.log( "isFIle : " + stats.isFile() );     // 파일 여부

console.log( "isDirectory : " + stats.isDirectory() );     // 디렉토리 여부

console.log( "isBlockDevice : " + stats.isBlockDevice() );     // 블럭타입의 기기 여부

console.log( "isCharacterDevice : " + stats.isCharacterDevice() );  // 문자타입의 기기 여부

console.log( "isSymbolicLink : " + stats.isSymbolicLink() );           // 심볼릭 링크 여부

console.log( "isFIFO : " + stats.isFIFO() );     // FIFO(유닉스 네임드 파이프) 여부

console.log( "isSocket : " + stats.isSocket() );     // 도메인 소켓 여부


} );


결과 


Stats {

  dev: 3296761668,

  mode: 33206,

  nlink: 1,

  uid: 0,

  gid: 0,

  rdev: 0,

  blksize: undefined,

  ino: 5348024557619625,

  size: 0,

  blocks: undefined,

  atimeMs: 1499646197248.9653,

  mtimeMs: 1510624392877.0774,

  ctimeMs: 1510624392877.0774,

  birthtimeMs: 1499646197248.9653,

  atime: 2017-07-10T00:23:17.249Z,

  mtime: 2017-11-14T01:53:12.877Z,

  ctime: 2017-11-14T01:53:12.877Z,

  birthtime: 2017-07-10T00:23:17.249Z }

=============================================================

isFIle : true

isDirectory : false

isBlockDevice : false

isCharacterDevice : false

isSymbolicLink : false

isFIFO : false

isSocket : false



2. fs.rename(source, target, callback);


파일명을 변경한다.


callback :

err<Error> : 에러 정보


fs.rename("D:\\temp\\out.log", "D:\\temp\\output.log", (err) => {

if( err) throw err;


fs.stat("D:\\temp\\output.log", (err, stats) => {

if( err) throw err;

console.log( stats );

});

});


결과는 파일 명을 변경하고 해당 파일 명의 정보를 출력한다.



3. fs.exists(file, callback);


파일의 존재 여부를 확인한다.


callback :

exists<Boolean> : 존재 여부

fs.exists("D:\\temp\\output.log", (exists) => {

console.log( exists ? "있음" : "없음" );

});



4.  fs.appendFile(file, data, callback);


파일에 내용을 추가한다.

파일이 존재하지 않을 경우 파일을 생성한다.


callback :

err<Error> : 에러 정보


fs.appendFile("D:\\input.txt", "Data to append....", (err) => {

if( err ) {

console.error(err);

return;

}


console.log("Data 추가 완료");

});



5. fs.open(file, flags[, mode], callback)


파일을 오픈할 때 사용된다. 


flags :


r        - 파일을 읽는다. 파일이 없을 경우 예외 발생

r+      - 파일을 읽고 쓴다, 파일이 없을 경우 예외 발생

w       - 파일을 쓴다. 파일이 없는 경우 생성하고 있는경우는 덮어 씌운다.

wx      - w와 비슷하지만 파일이 있는경우 실패한다.

w+     - 파일을 읽고 쓴다. 파일이 없는 경우 생성하고 있을경우 덮어 씌운다.

wx+    - w+와 비슷하지만 파일이 있는경우 실패한다.

a        - 파일을 추가한다. 파일이 없는 경우 생성한다.

ax      - a와 비슷하지만 파일이 있는경우 실패한다.

a+      - 파일을 읽고 추가한다. 파일이 없으면 생성한다.

ax+    - a+와 비슷하지만 파일이 없는 경우 실패한다.


callback :

err<Error> :   에러 정보

fd<integer> :  타입의 결과값  



fs.open("D:\\temp\\out.log", "wx", (err, fd) => {

if( err ) {


if( err.code == "ENOENT" ) {

console.error( "파일이 존재하지 않음.");

return;

} else if( err.code = "EEXIST" ) {

console.error( "이미 파일이 있습니다.");

return;

}


throw err;

}


console.log( fd );

});



6. fs.readFile(file[, options], callback)


파일 내용을 읽는다.


callback :

err<Error> : 에러정보

data<String|Buffer> : 파일 내용


나는 input.txt 라는 파일 생성하고 내용에 "Test File System.."이라고 입력 후 저정하였다.


옵션 없이 실행할 경우와 있는 경우의 data 값은 다르게 출력이 된다.

옵션이 없는 경우 기본적으로 인코딩되어 출력이 된다.



// 옵션이 없는 경우

fs.readFile("D:\\input.txt", (err, data) => {

if( err ) {

console.error("read file error : " + err );

return;

}


console.log( data );

});


결과 :


<Buffer 54 65 73 74 20 46 69 6c 65 20 53 79 73 74 65 6d 2e 2e>


//옵션이 있는 경우

fs.readFile("D:\\input.txt", "utf8", (err, data) => {

if( err ) {

console.error("read file error : " + err );

return;

}


console.log( data );

});


결과 :


Test File System..



7. fs.writeFile(file, data[, options], callback)


파일을 쓴다.


callback :

err<Error> : 에러 정보


fs.writeFile("D:\\test.txt", "hello world", (err) => {

if( err ) {

console.error("write file error : " + err );

return;

}


console.log("write completed..");

});


결과 :


write completed..


파일을 읽거 나 쓸 경우 위의 방식이 아닌 fis.open()을 사용하고 fs.read() 와 fs.write()를 사용할 수 있다.


파일 읽기 :


fs.open("D:\\test.txt", "r", (err, fd) => {


if( err ) {

console.error("open error : " + err );

return;

}


var buf = new Buffer(5);

fs.read(fd, buf, 0, buf.length, null, (err, byteRead, buffer) => {


if( err ) {

console.error("read error : " + err );

return;

}


console.log( err, byteRead, buffer);


fs.close(fd, () => {

console.log( "Done." );

});

});

});


결과 :


null 5 <Buffer 61 64 64 20 44>

Done.


파일 쓰기 :


fs.open("D:\\test.txt", "w", (err, fd) => {

if( err ) {

console.error("open error : " + err );

return;

}


var buf = new Buffer("add Data...\n");

fs.write(fd, buf, 0, buf.length, null, (err, written, buffer)=> {

if( err ) {

console.error("write error : " + err );

return;

}


console.log( err, written, buffer);


fs.close(fd, () => {

console.log( "Done." );

});

} );


});


결과 :


null 12 <Buffer 61 64 64 20 44 61 74 61 2e 2e 2e 0a>

Done.


맘은 더 쓰고 싶은데...ㅡㅡ

귀찮다.. 나머지는 찾으면서~~

path 모듈 로딩 필요


var path = require("path");


path모듈은 Windows와 POSIX에서의 결과가 다르게 나타난다.


POSIX : 


path.basename("D:\\temp\\out.log");

==> output : D:\temp\out.log


WINDOWS :


path.basename("D:\\temp\\out.log");

==> output : out.log


운영체제에 따라 위와 같이 다른 결과가 나타난다.


이러한 문제점을 해결하기 위해 일관된 결과를 얻고자 할 경우에는 다음과 같이 한다.


Windows 에서 출력되는 것 처럼 하고자 할 경우


path.win32.basename("D:\\temp\\out.log");

==> out.log


POSIX에서 출력되는 것 처럼 하고자 할 경우


path.posix.basename("D:\\temp\\out.log");

==> output : D:\temp\out.log





1. path.basename(경로 [, 파일확장자(선택사항)])


경로의 마지막 부분 반환한다.


path.basename("D:\\temp\\out.log");

==> output : out.log


path.basename("D:\\temp\\out.log", ".log");

==> output : out



2. path.dirname(경로)


디렉토리명을 반환한다.


path.dirname("D:\\temp\\logs\\20171113\\out.log");

==> output : D:\temp\logs\20171113




3. path.extname(경로)


파일의 확장자 명을 출력한다.


path.extname('index.html');

==> output : '.html'


path.extname('index.coffee.md');

==> output : '.md'


path.extname('index.');

==> output : '.'


path.extname('index');

==> output : ''


path.extname('.index');

==> output : ''



4. path.parse(경로)


경로를 구성하고 있는 중요 요소를 출력한다.


path.parse('/home/user/dir/file.txt');

==> output : 

{ root: '/',

   dir: '/home/user/dir',

   base: 'file.txt',

   ext: '.txt',

   name: 'file' }


위의 예제 말고도 path.normalize, path.join ([... paths]), path.isAbsolute (path), path.format (pathObject), path.delimiter 이 더 있다.

그런데 잘 쓸거 같지 않아서 넘어간다.


필요 시 API 참조...ㅋ

Event는 기본적으로 리스너(Listener)에 이벤트를 등록하고 Emitter를 통하여 해당 Listener를 호출 하는 실행 된다.


책을 읽으려 하니 나는 책이 이해가 잘 가지않는...다...


에혀...ㅋㅋ 내가 많이 부족한가 보다...


모 여튼.. 그러하더라도 책에는 Event 를 3가지로 구분하고 있다.


1. 표준 콜백 패턴


함수가 작업을 마친 후 콜백 함수를 호출함으로써 프로그램을 이어가는 방식이다.


var fs = require("fs");

fs.readFile("/etc/passwd", function(err, fileContent) {

if( err ) throw err;

console.log("파일 내용 : " + fileContent);

});



2. 이벤트 이미터 패턴


콜백 패턴은 하나의 함수 실행 후 하나의 이벤트에 대한 처리에는 적합하지만, 함수 실행 후 다수의 이벤트에 대한 처리는 어렵다.


이런 경우 사용하는 패턴이 이벤트 이미터 패턴이다.



var http = require("http");

var options = {

host: "localhost",

port: "8081",

path: "/index.html"

};


var req = http.request(options, function(response) {

response.on("data", (data) => {

console.log("수신된 데이터 : " + data);

});


response.on("end", () => {

console.log( "응답종료" );

});

});

req.end();


위의 예제는 서버의 index파일을 읽어 들여 출력하는 것이다.

위와 같이 함수가 실행된 후 이벤트가 여러번(시작, 전송, 종료 등) 필요할 때 사용되는 패턴이다.



3. 이벤트 타입


내가 이해한것이 맞다면 이것은 사용자가 직접 이벤트를 작성하고 등록하는 형태이다.


작성법은


//events 모듈 로드

var events = require("events");


//EventEmitter 객체 생성

var emitter = new events.EventEmitter();


//event와 EventHandler을 연동(Listener에 등록)

emitter.on("eventName", eventHandler);


//연동되어 있는(Listener에 등록되어 있는) event 실행

emitter.emit("eventName");


다음은 예제이다.


var emitter = new (require('events')).EventEmitter();


emitter.on("event", () => {

console.log("event 실행...");

});


emitter.emit("event");



4. 이벤트 연결(등록)


emitter.addListener(event, listener);

emitter.on(event, listener);

emitter.once(event, listener);


addListener과 on은 동일한 것이다.

이 두가지는 이벤트를 지속하여 연결하고 잇는 것이지만 once 는 한 번 연결 후 제거 된다.


process 객체를 예를 들면 다음과 같다.



process.addListener("exit", () => {

console.log("Exit Event");

});


process.on("exit", (data) => {

console.log("종료코드 : " + data );

});


process.once("uncaughtException", (err) => {

console.log( "exception listener count[2nd] : " + process.listenerCount("uncaughtException") );

console.log( "exit listener count[2nd] : " + process.listenerCount("exit") );

console.log("----------------------------------------------------");

});


console.log( "exception listener count[1st] : " + process.listenerCount("uncaughtException") );

console.log( "exit listener count[1st] : " + process.listenerCount("exit") );

console.log("----------------------------------------------------");


noneistenFunc();

console.log("예외가 발생으로 실행 되지 않음.");


위의 소스를 실행하면 다음과 같다.


exception listner count[1st] : 1

exit listner count[1st] : 2

----------------------------------------------------

exception listner count[2nd] : 0

exit listner count[2nd] : 2

----------------------------------------------------

Exit Event

종료코드 : 0


보는 바와 같이 exit 이벤트는 2개가 계속 유지 되지만 once 를 사용한 uncaughtException는 한번 실행 후  count가 0임을 확인할 수 있다.

위의 소스의 특이점은 exit 이벤트가 두번 등록이 되어 있는 것을 확인할 수 있을 것이다.
이벤트는 다수의 명칭으로 등록할 수 있으며 해당 이벤트를 실행 시 등록 순서대로 해당 Listener를 호출하게 된다.

주의 할 점은 이벤트 리스너가 실행 되는 도중 Exception이 발생할 경우 다른 이벤트 리스너가 실행 되지 않을 수 있다.

process.addListener("exit", () => {
throw new Error("오류가 발생하였습니다.");
});

process.on("exit", (data) => {
console.log("종료코드 : " + data );
});

위의 결과는 

D:\Develop\Workspace\Neon\NodeJs\event2.js:5
throw new Error("오류가 발생하였습니다.");
^

Error: 오류가 발생하였습니다.
    at process.addListener (D:\Develop\Workspace\Neon\NodeJs\event2.js:5:8)
    at emitOne (events.js:121:20)
    at process.emit (events.js:211:7)

이와 같이 종료코드 : 0 이 출력되지 않고 실행이 되지 않은것을 확인 할 수 있다.



5. 이벤트 제거


emitter.removeListener(event, listener);

emitter.removeAllListener([event]);


등록되어 있는 이벤트를 제거하기 위해 사용된다.


var exitListener = function() {

    console.log('프로그램 종료[1st]');

};


// 이벤트 연결

process.on('exit', exitListener);


process.on('exit', ()=> {

console.log("프로그램 종료[2nd]")

});


// 이벤트 제거

process.removeListener('exit',exitListener);


결과 : 


프로그램 종료[2nd]







'JavaScript > NodeJS' 카테고리의 다른 글

[NodeJS] File System  (0) 2017.11.16
[NodeJS] Path  (0) 2017.11.13
[NodeJS] 모듈, 캐싱 그리고 exports  (0) 2017.11.08
[NodeJS] Callback Function, Blocking Code, Non-Blocking Code  (0) 2017.11.07
[NodeJS] 내장모듈 사용  (0) 2017.11.07

1. 사용자 모듈 생성


모듈은 java나 C의 라이브러리라고 보면 된다.


모듈은 javascript 파일 단위로 구현이 되며 해당 파일 안에서 exports를 해야만 사용이 가능하다.


가장 기본적인 구조는 다음과 같다.


// calc.js

function add(a, b) {

return a + b;

}


module.exports = add;



이와 같이 하여  사용시에는 require 하여 사용하면 됩니다.


var add = require("./calc");

console.log(add(1,2));    //3



이를 확장하여 javascript 파일 하나에 여러개의 기능을 추가하고 싶을 경우는


//calc.js

function add(a, b) {

return a + b;

}


function substract(a, b) {

return a - b;

}


function multiply(a, b) {

return a * b;

}


function divide(a, b) {

return a / b;

}


module.exports = {

add : add,

substract : substract,

multiply : multiply,

divide : divide

};


이와 같이 작성을 하면 된다.


위의 소스 에서 module.export 할 때 형태를 다음과 같이 개별로 구분하여도 상관은 없다.


exports.add = add;

exports.substract = substract ;

exports.multiply= multiply;

exports.divide= divide;


단일 함수를 사용할 경우에는 module를 삭제해도 상관이 없다. 그러니까 여러 객체를 따로 exports 할 때만 사용한다.

이러한 방식으로 사용할 경우 exports에 바로 다른 값을 대입하면 안된다는 것이다.


exports = add;


이렇게 작업을 함과 동시에 NodeJS는 제대로 기능을 하지 않는다.




또 다른 방법으로는 


//calc2.js

module.exports = function(a, b) {


return {

add : function(){

return a + b;

},


substract : function() {

return a - b;

},


multiply : function() {

return a * b;

},


divide : function() {

return a / b;

}

};

};


이와 같이 작성을 하여도 된다.

하지만 위와 같이 작성하였을 경우에는 초기화 작업이 한번 들어가야 한다.

사용법은 아래와 같다.


var calc2 = require("./calc2");


var myCalc = calc2(1, 2);

console.log( myCalc.add() );     // 3




2. 파일 모듈 로딩


파일 모듈 로딩은 코어 모듈 로딩, 파일 모듈 로딩 방식과 폴더 모듈 로딩 방식이 있다.

말 그대로 파일모듈로딩은 파일을 폴더 모듈로딩은 폴더의 파일들을 묶어서 로딩할 수 있는 Java의 package와 같다고 보면 된다.


- 코어 모듈 로딩


코어 모듈은 NodeJS에서 제공하는 모듈이다.

코어 모듈은 경로가 아닌 모듈명 참조로 로딩하며 같은 이름의 서드파티 모듈이 존재하다라도 우선적으로 로드된다.


var http = require("http");


코어 모듈은 API를 참조 하면 된다.


- 파일 모듈 로딩


파일 모듈은 코어 모듈이 아닌 모듈로서 로딩시 절대 경로 또는 상대경로로 지정하여 로딩한다.


//절대 경로

var myModule = require("/home/nodejsDir/mymodule");


//상대 경로

var myModule2 = require("./nodejsDir/mymodule");

var myModule3 = require("./nodejsDir/mymodule.js");


이와 같이 로딩되며 로딩할 때 확장자인 .js는 생략해도 무관하다.


만약 js가 생략되었을 경우 우선적으로 해당 명칭의 모듈 파일을 로딩하고 없으면 폴더를 검색하게 된다.




- 폴더 모듈 로딩


폴더 모듈로딩은 폴더의 파일들을 묶어서 로딩할 수 있는 Java의 package와 같다고 보면 된다.


var myModuleDir = require("./nodejsDir");


이렇게 선언하면 해당 폴더 내의 모듈을 찾는다.

NodeJS는 이 폴더를 package라고 판단을 하여 package.json 파일을 찾는다.


해당 폴더에 package.json 파일이 없으면 package의 기본 모듈인 index.js 또는 index.node를 찾는다.



packate.json는 아래와 같이 작성할 수 있다.


{

"name" : "calc",

"main" : "./calc.js"        //nodejsDir에 있다고 가정한다.

}




3. 모듈 캐싱


모듈은 처음 로딩 될때 캐싱된다.

결과적으로 한번만 로딩이 되어 여러번 호출 한다해도 반환되는 모듈은 항상 동일하다.


//mymodule.js

console.log("myModule 시작");

module.exports = function() {

console.log( "myModule 호출");

};

console.log("myModule 끝");


위의 모듈을 로딩하고 나면 


var myModule = require("./mymodule");


다음과 같이 결과가 출력된다.


myModule 시작

myModule 끝


그럼 다음과 같이 두번 호출 한다고 해보자


var myModule1 = require("./mymodule");

var myModule2 = require("./mymodule");


그래도 결과는 


myModule 시작

myModule 끝


반복하여 출력하는 것이 아니라 한번만 출력이 되는 것을 확인 할 수 있을 것이다.


이는 해당 모듈은 초기화가 한번만 일어난다는 의미임을 알 수 있다.





1. Callback Function


NodeJS는 Event driven programming(이벤트 반응형 프로그램) 개념을 가지고 있으며, 이 개념은 특정 이벤트가 발생되면 미리 이벤트에 Binding 된 함수가 실행 되는 것이다. 결과 적으로 해당 함수가 언제 호출되는지 알 수가 없다.


이처럼 Binding되어 실행된 결과를 처리하는 함수를 Callback Function라고 하는데...


예를 들어 jQuery에서 사용된 Callback Function 살펴보자.


var callback = function(result) {

console.log("Callback Data : " + result);

}


$.get("/endpoint", callback);


이와 같이 callback 함수는 $.get() 이 실행되어 결과값이 올때에만 실행 되어진다.


이러한 이벤트 방식은 Windows나 Java Swing 같은 GUI 프로그램에서 Mouse Event 발생 시 사용되는 Callback 함수와 동일 하다고 볼 수 있다.


왜 이렇게 장황하게 Callback Function에 대해서 나열을 하냐면... 음...


NodeJS는 Event 를 발생해 놓고, 코드를 Blocking 상태에서 기다리게 하는 것이 아니라, Event에 대한 요청이 끝나면 미리 Binding 해 놓은 Callback 함수를 실행하는 형태(Non-Blocking)이다. 한마디로 비동기 형식....??




2. Blocking Code


일반적으로 사용하는 Programming 형태라고 할 수 있다.

코드가 순차적으로 실행되면서 어떠한 이벤트 또는 함수가 완료 될 때까지 진행하지 않고 기다리는 형태이다.


var fs = require("fs");


var data = fs.readFileSync("hello.txt");


console.log(data.toString());

console.log("프로그램 종료");


해당 소스의 결과는 


안녕하세요, Hello World 입니다.

프로그램 종료


이렇게 순차적으로 파일을 읽은 후 파일 내용을 출력하고 마지막으로 프로그램종료를 출력하게 된다.




3. Non-Blocking Code


Blocking Code와 다르게 실행 함수가 끝날때 까지 기다리는 것이 아니라 바로 아래 코드를 실행하고, 실행 함수의 작업이 다 끝나면 Callback Function 를 호출하는 형태이다.


한마디로 던져 놓고 결과가 올때까지 기다리는 비동기 형태의 프로그램이라고 할 수 있다.


var fs = require("fs");


fs.readFile("hello.txt", function(err, data) {

if( err ) return console.error(err);    //오류 출력

console.log(data.toString());

});


console.log("프로그램 종료");


해당 소스의 결과는 


프로그램 종료

안녕하세요, Hello World입니다.


결과 적으로 fs.readFile() 함수가 끝나기 전에 바로 다음 명령을 실행하게 됩니다.

그렇다고 하여 프로그램이 종료 된것은 아니고 fs.readFile() 함수가 종료 될때 까지 기다리게 된다.








내장모듈에서 자주 사용하는 모듈에 대해서 설명을 해드리겠습니다.


os 모듈 : OS 관련 정볼르 보여주고, 전역객체인 Process 객체와 비슷하지만, 좀 더 많은 정보를 제공하는 모듈


var os = require("os");

console.log(os.hostname());   // 호스트 이름

console.log(os.type());          // os 이름

console.log(os.platform());    // 플랫폼

console.log(os.totalmem());  // 시스템 총 메모리

console.log(os.freemem());   // 시스템 가용 메모리

console.log(os.cpus());        // cpu 정보 객체

console.log(os.networkInterfaces()); // 네트워크 인터페이스 정보




url 모듈 : URL에서 정보를 추출하거나 변환해주는 모듈


var url = require("url");

var urlStr = 'https://nodejs.org/dist/latest-v4.x/docs/api/';

var urlObj = url.parse(urlStr); // URL 문자열을 URL 객체로 변환

console.log(urlObj);


/* 실행결과

Url {

  protocol: 'https:',

  slashes: true,

  auth: null,

  host: 'nodejs.org',

  port: null,

  hostname: 'nodejs.org',

  hash: null,

  search: null,

  query: null,

  pathname: '/dist/latest-v4.x/docs/api/',

  path: '/dist/latest-v4.x/docs/api/',

  href: 'https://nodejs.org/dist/latest-v4.x/docs/api/' }

*/



querystring 모듈 : URL 객체의 쿼리와 관련있는 모듈


var queryString = require("queryString")

queryString.stringify(obj [. ...]); // 쿼리 객체를 쿼리 문자열로 변환

queryString.parse(str, [, ..]); // 쿼리 문자열을 쿼리 객체로 변환




util 모듈 : 보조적인 기능을 하는 모듈


var util = require('util');

var data = util.format('%d + %d = %d' , 52, 23, 52+23);

console.log(data);  // 52 + 23 = 75



출처: http://ourcstory.tistory.com/56 [쌍쌍바나나의 블로그]

+ Recent posts