노드는 운영체제 정보에도 접근할 수 있고, 클라이언트가 요청한 주소에 대한 정보 등 웹 브라우저에서 사용되는 자바스크립트보다 더 많은 기능을 제공한다.
웹 브라우저에서 사용되는 자바스크립트는 운영체제의 정보를 가져올 수 없지만, 노드는 os모듈에 정보가 담겨 있어 정보를 가져올 수 있다.
os라는 파일이 존재하는 것은 아니지만 require('os')
혹은 require('node:os')
로 내장 모듈인 os를 불러올 수 있다.
속성과 메서드
os.type()
: 운영체제의 종류os.uptime()
: 운영체제 부팅 이후 흐른 시간(초)os.hostname()
: 컴퓨터의 이름os.release()
: 운영체제의 버전os.homedir()
: 홈 디렉토리 경로os.tmpdir()
: 임시 파일 저장 경로os.cpus()
: 컴퓨터의 코어 정보os.freemem()
: 사용 가능한 메모리(RAM)os.totalmem()
: 전체 메모리 용량폴더와 파일의 경로를 쉽게 조작하도록 도와주는 모듈.
path 모듈이 필요한 이유 중 하나는 운영체제별로 경로 구분자가 다르기 때문이다.
'\'
백슬래시로 구분한다.'/'
슬래시로 구분한다.속성과 메서드
path.sep
: 경로의 구분자. 윈도는 '\', POSIX는 '/'path.delimiter(경로)
: 환경 변수의 구분자. process.env.PATH를 입력하면 여러 개의 경로가 이 구분자로 구분되어 있다. win은 세미콜론(;), POSIX는 콜론(:)path.extname(경로)
: 파일의 확장자.path.basename(경로, 확장자)
: 파일의 이름(확장자 포함)을 표시. 파일의 이름만 표시하고 싶다면 두 번째 인수로 파일의 확장자를 넣으면 된다.path.parse(경로)
: 파일 경로를 root, dir, base, ext, name으로 분리.path.format(객체)
: path.parse()한 객체를 파일 경로로 합친다.path.normalize(경로)
: '/'나 '\' 를 실수로 여러 번 사용했거나 혼용했을 때 정상적인 경로로 변환한다.path.isAbsolute(경로)
: 파일의 경로가 절대경로인지 상대경로인지를 bool값으로 알린다.path.relative(기준경로, 비교경로)
: 경로를 두 개 넣으면 첫 번째 경로에서 두 번째 경로로 가는 방법을 알린다.path.join(경로, ...)
: 여러 인수를 넣으면 하나의 경로로 합친다. 상대경로인 ..(부모 디렉터리)과 .(현 위치)도 알아서 처리.path.resolve(경로, ...)
: path.join()과 비슷하지만 차이가 있다.join과 resolve의 차이
path.join과 path.resolve 메서드는 비슷해 보이지만 동작 방식이 다르다. /를 만나면 path.resove는 정대 경로로 인시갷서 앞의 경로를 무시하고, path.join은 상대 경로로 처리한다.path.join('/a', '/b', 'c'); // /a/b/c path.resolve('/a', '/b', 'c') // /b/c
인터넷 주소를 쉽게 조작하도록 도와주는 모듈.
new URL
const url = require("url"); // --- ①
const { URL } = url;
const myURL = new URL('http://www.gilbut.co.kr/book/booklist.aspx?sercate1=001001000#anchor');
console.log('new URL():' , myURL);
console.log('url.format():' , url.format(myURL));
① URL 생성자에 주소를 넣어 객체로 만들면 주소가 부분별로 정리된다.
URL은 노드 내장 객체이기도 해서 require
할 필요는 없다)
url.format(객체)
: 분해되었던 url 객체를 다시 원래 상태로 조립$ node url
new URL(): URL {
href: 'http://www.gilbut.co.kr/book/booklist.aspx?sercate1=001001000#anchor',
origin: 'http://www.gilbut.co.kr',
protocol: 'http:',
username: '',
password: '',
host: 'www.gilbut.co.kr',
hostname: 'www.gilbut.co.kr',
port: '',
pathname: '/book/booklist.aspx',
search: '?sercate1=001001000',
searchParams: URLSearchParams { 'sercate1' => '001001000' },
hash: '#anchor'
}
searchParmas
search
부분(쿼리 스트링)은 보통 주소를 통해 데이터를 전달할 때 사용된다. ?
로 시작하고 키=값
형식으로 데이터를 전달한다. 여러 키가 있을 경우에는 &
로 구분한다.
const myURL = new URL("http://www.gilbut.co.kr/?page=3&limit=10&category=nodejs&category=javascript");
console.log("searchParams:", myURL.searchParams);
console.log("searchParams.getAll():", myURL.searchParams.getAll("category"));
console.log("searchParams.get():", myURL.searchParams.get("limit"));
console.log("searchParams.has():", myURL.searchParams.has("page"));
console.log("searchParams.keys():", myURL.searchParams.keys());
console.log("searchParams.values():", myURL.searchParams.values());
myURL.searchParams.append("filter", "es3");
myURL.searchParams.append("filter", "es5");
console.log(myURL.searchParams.getAll("filter"));
myURL.searchParams.set("filter", "es6");
console.log(myURL.searchParams.getAll("filter"));
myURL.searchParams.delete("filter");
console.log(myURL.searchParams.getAll("filter"));
console.log("searchParams.toString():", myURL.searchParams.toString());
myURL.search = myURL.searchParams.toString();
$ node searchParams
searchParams: URLSearchParams {
'page' => '3',
'limit' => '10',
'category' => 'nodejs',
'category' => 'javascript' }
searchParams.getAll(): [ 'nodejs', 'javascript' ]
searchParams.get(): 10
searchParams.has(): true
searchParams.keys(): URLSearchParams Iterator { 'page', 'limit', 'category', 'category' }
searchParams.values(): URLSearchParams Iterator { '3', '10', 'nodejs', 'javascript' }
[ 'es3', 'es5' ]
[ 'es6' ]
[]
searchParams.toString(): page=3&limit=10&category=nodejs&category=javascript
URL 생성자를 통해 만들어진 인스턴스에는 searchParams
객체가 있다. 이 객체는 search 부분을 조작하는 다양한 메서드를 지원한다.
new URLSearchParams(myURL.search)
로도 같은 결괏값을 얻을 수 있다.
getAll(key)
: 키에 해당하는 모든 값을 가져온다.get(key)
: 키에 해당하는 첫 번째 값만 가져온다.has(key)
: 해당 키가 있는지 없는지를 검사한다.keys()
: searchParams의 모든 키를 Iterator 객체로 가져온다.values()
: searchParams의 모든 값을 Iterator 객체로 가져온다.append(key, value)
: 해당 키를 추가한다. 같은 키의 값이 있다면 유지하고 하나 더 추가한다.set(key, value)
: append와 비슷하지만 같은 키의 값들을 모두 지우고 새로 추가한다.delete(key)
: 해당 키를 제거한다.toString()
: 조작한 searchParams 객체를 다시 문자열로 만든다. 이 문자열을 search에 대입하면 주소 객체에 반영된다.DNS를 다룰 때 사용하는 모듈이다. 주로 도메인을 통해 IP나 기타 DNS 정보를 얻고자 할 때 사용한다.
import dns from 'dns/promises';
const ip = await dns.lookup('gilbut.co.kr');
console.log('IP', ip);
const a = await dns.resolve('gilbut.co.kr', 'A');
console.log('A', a);
const mx = await dns.resolve('gilbut.co.kr', 'MX');
console.log('MX', mx);
const cname = await dns.resolve('www.gilbut.co.kr', 'CNAME');
console.log('CNAME', cname);
const any = await dns.resolve('gilbut.co.kr', 'ANY');
console.log('ANY', any);
$ node dns.mjs
IP { address: '49.236.151.220', family: 4 }
A [ '49.236.151.220' ]
MX [
{ exchange: 'aspmx.l.google.com', priority: 1 },
{ exchange: 'alt2.aspmx.l.google.com', priority: 5 },
{ exchange: 'aspmx2.googlemail.com', priority: 10 },
{ exchange: 'aspmx3.googlemail.com', priority: 10 },
{ exchange: 'alt1.aspmx.l.google.com', priority: 5 }
]
CNAME [ 'slb-1088813.ncloudslb.com' ]
ANY [
{ value: 'ns1-2.ns-ncloud.com', type: 'NS' },
{ value: 'ns1-1.ns-ncloud.com', type: 'NS' },
{
nsname: 'ns1-1.ns-ncloud.com',
hostmaster: 'ns1-2.ns-ncloud.com',
serial: 76,
refresh: 21600,
retry: 1800,
expire: 1209600,
minttl: 300,
type: 'SOA'
}
]
ip 주소는 간단하게 dns.lookup이나 dns.resolve(도메인)으로 얻을 수 있다. A(ipv4 주소), AAAA(ipv6 주소), NS(네임서버), SOA(도메인 정보), CNAME(별칭), MX(메일 서버) 등 레코드라고 부르는데 해당 레코드에 대한 정보는 dns.resolve(도메인, 레코드 이름)
으로 조회 가능하다.
다양한 방식의 암호화를 도와주는 모듈이다.
단방향 암호화란 복호화할 수 없는 암호화 방식을 뜻한다.
복호화는 암호화된 문자열을 원래 문자열로 되돌려 놓는 것을 의미한다. 즉, 단뱡향 암호화는 한번 암호화하면 원래 문자열을 찾을 수 없다.
복호화가 불가능하기 때문에 암호화 대신 해시 함수라고 부르기도 한다.
단방향 알고리즘은 주로 해시 기법을 사용한다. 해시 기법이란 어떠한 문자열을 고정된 길이의 다른 문자열로 바꿔버리는 방식이다.
const crypto = require("crypto");
console.log('base64:', crypto.createHash('sha512').update('비밀번호').digest('base64'));
console.log('hex:', crypto.createHash('sha512').update('비밀번호').digest('hex'));
console.log('base64:', crypto.createHash('sha512').update('다른 비밀번호').digest('base64'));
$ node hash
base64: dvfV6nyLRRt3NxKSlTHOkkEGgqW2HRtfu19Ou/psUXvwlebbXCboxIPmDYOFRIpqav2eUTBFuHaZri5x+usy1g==
hex: 76f7d5ea7c8b451b773712929531ce92410682a5b61d1b5fbb5f4ebbfa6c517bf095e6db5c26e8c483e60d8385448a6a6afd9e513045b87699ae2e71faeb32d6
base64: cx49cjC8ctKtMzwJGBY853itZeb6qxzXGvuUJkbWTGn5VXAFbAwXGEOxU2Qksoj+aM2GWPhc1O7mmkyohXMsQw==
createHash(알고리즘)
: 사용할 해시 알고리즘을 넣는다. md5, sha1, sha256, sha512 등이 가능하지만 md5와 sha1은 취약점이 발견되었다. 현재 sha512 정도로 충분하지만 sha512도 취약해지면 더 강화된 알고리즘으로 바꾸어야 한다.update(문자열)
: 변환할 문자열을 넣는다.digest(인코딩)
: 인코딩할 알고리즘을 넣는다. base64, hex, latin1이 주로 사용되며, 그중 base64가 결과 문자열이 가장 짧아서 애용된다. 결과물로 변환된 문자열을 반환한다.PBKDF2(Password-Based Key Derivation Function version 2)
주로 pbkdf2나 bcrypt, scrypt 알고리즘으로 패스워드를 암호화하는데 그중에서도 pbkdf2는 기존 문자열에 salt라고 불리는 문자열을 붙인 후 해시 알고리즘을 반복해서 적용하는 방식이다.
const crypto = require("crypto");
crypto.randomBytes(64, (err, buf) => {
const salt = buf.toString("base64");
console.log("salt:", salt);
crypto.pbkdf2("비밀번호", salt, 100000, 64, "sha512", (err, key) => {
console.log("password", key.toString("base64"));
});
});
randomBytes()
메서드로 64바이트 길이의 문자열을 만들면 이것이 salt
가 된다. pbkdf2()
메서드에는 순서대로 비밀번호, salt, 반복 횟수, 출력 바이트, 해시 알고리즘을 인수로 넣는다.
randomBytes
이므로 매번 실행할 때마다 결과가 달라지므로 salt를 잘 보관해야만 비밀번호도 찾을 수 있다.대칭키
암호화된 문자열을 복호화할 수 있으며, 키(열쇠)가 사용된다.
암호를 복호화 하려면 암호화할 때 사용한 키와 같은 키를 사용해야 한다.
const crypto = require("crypto");
const algo = "aes-256-cbc";
const key = "abcdefghijklmnopqrstuvwxyz123456";
const iv = "1234567890123456";
const cipher = crypto.createCipheriv(algo, key, iv);
let result = cipher.update("암호화할 문장", "utf8", "base64");
result += cipher.final("base64");
console.log("암호화:", result);
const decipher = crypto.createDecipheriv(algo, key, iv);
let result2 = decipher.update(result, "base64", "utf8");
result2 += decipher.final("utf8");
console.log("복호화", result2);
crypto.createCipheriv(알고리즘, 키, iv)
: 암호화 알고리즘과 키, iv를 넣는다. aes-256-cbc
알고리즘의 경우 키는 32바이트여야 하고, iv는 16바이트여야 한다. iv는 암호화할 때 사용하는 초기화 벡터를 의미한다.crypto.getCipher()
를 호출하면 사용 가능한 알고리즘 목록을 볼 수 있다. cipher.update(문자열, 인코딩, 출력 인코딩)
: 암호화할 대상과 대상의 인코딩, 출력 결과물의 인코딩을 넣는다. 보통 문자열은 utf8, 암호는 base64를 많이 용한다.cipher.createDecipheriv(알고리즘, 키, iv)
: 복호화할 때 사용한다. 암호화할 떄 사용했던 알고리즘과 키, iv를 그대로 넣어야 한다.decipher.update(문자열, 인코딩, 출력 인코딩)
: 암호화된 문장, 그 문장의 인코딩, 복호화할 인코딩. createCipheriv.update()
에서 utf8, base64순으로 넣었다면 base64, utf8 순으로 넣으면 된다.decipher.final(출력 인코딩)
: 복호화할 결과물의 인코딩을 넣는다.crypto 모듈은 다양한 암호화를 제공하고 있으니 어떤 메서드를 지원하는지 공식 문서에서 확인이 가능하다.
https://nodejs.org/api/crypto.html
각종 편의 기능을 모아둔 모듈이다. 계속 API가 추가되고 있으며 desperated
되어 사라지는 경우도 있다.
deprecated?
프로그래밍 용어로, '중요도가 떨어져 더 이상 사용되지 않고 앞으로는 사라지게 될'이라는 뜻. 새로운 기능이 나와서 기존 기능보다 더 좋을 때, 기존 기능을 desperated 처리하곤 한다. 이전 사용자를 위해 제거하지는 않지만 곧 없앨 예정이르모 더 이상 사용하지 말라는 의미다.
const util = require("util");
const crypto = require("crypto");
const dontUseMe = util.deprecate((x, y) => {
console.log(x + y);
}, "dontUseMe 함수는 desperted 되었으니 더 이상 사용하지 마세요!");
dontUseMe(1, 2);
const randomBytesPromise = util.promisify(crypto.randomBytes);
randomBytesPromise(64)
.then((buf) => {
console.log(buf.toString("base64"));
})
.catch((err) => {
console.log(err);
});
util.deprecatedd
: 함수가 deprecated 처리되었음을 알린다. 첫 번재 인수로 넣은 함수를 사용했을 때 경고 메시지가 출력된다. 두 번째 인수로 경고 메시지 내용을 넣으면 된다.util.promisify
: 콜백 패턴을 프로미스 패턴으로 바꾼다. 바꿀 함수를 인수로 제공하면 된다.worker_threads
: 노드에서 멀티 스레드 방식으로 작업하기 위한 모듈들을 제공한다.child_process
: 노드에서 다른 프로그램을 실행하고 싶거나 명령어를 수행하고 싶을 때 사용 하는 모듈. 다른 언어의 코드를 실행하고 결괏값을 받을 수 있다.async_hooks
: 비동기 코드의 흐름을 추적할 수 있는 실험적인 모듈dgram
: UDP와 관련된 작업을 할 때 사용.net
: HTTP보다 로우 레벨인 TCP나 IPC 통신을 할 때 사용.pref_hooks
: 성능 측정을 할 때 console.time 보다 더 정교하게 측정queryString
: URLSearchParams가 나오기 이전에 쿼리스트링을 다루기 위해 사용했던 모듈. 근래엔 URLSearchParams을 사용하는 것을 권장.string_decoder
: 버퍼 데이터를 문자열로 바꾸는 데 사용.tls
: TLS와 SSL에 관련된 작업을 할 때 사용tty
: 터미널과 관련된 작업을 할 때 사용v8
: v8엔진에 직접 접근할 때 사용vm
: 가상 머신에 직업 접근할 댸 사용wasi
: 웹어셈블리를 실행할 댸 사용하는 실험적인 모듈