Node js:NodeJS ์ด์šฉํ•œ ์„œ๋ฒ„ ๋งŒ๋“ค๊ธฐ

@choi2021 ยท October 18, 2022 ยท 8 min read

nodejs
nodejs

๐ŸŽˆ Node JS๋ž€

๋…ธ๋“œ JS๋Š” ๋ธŒ๋ผ์šฐ์ €๋ฐ–์—์„œ๋„ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ๋Ÿฐํƒ€์ž„ ํ™˜๊ฒฝ์ด๋‹ค. single thread ์–ธ์–ด์ธ Javascript๊ฐ€ ๋ธŒ๋ผ์šฐ์ € ์œ„์—์„œ browser API๋ฅผ ์ด์šฉํ•œ ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ๋กœ ๋‹ค์–‘ํ•œ ์ผ์„ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ์—ˆ๋˜ ๊ฒƒ ์ฒ˜๋Ÿผ, Node JS ๋˜ํ•œ, ์ž์ฒด API๋ฅผ ์ด์šฉํ•ด์„œ ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ๋ฅผ ์ด์šฉํ•ด ๋‹ค์–‘ํ•œ ๊ธฐ๋Šฅ์„ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ๊ณ , brower์ฒ˜๋Ÿผ Event๋ฅผ ํ†ตํ•ด์„œ ์ฝœ๋ฐฑ์„ ์‹คํ–‰ํ•˜๋Š” ํŠน์ง•์„ ๊ฐ€์ง„๋‹ค.

์ด๋Ÿฌํ•œ ๊ธฐ๋Šฅ์ค‘์—์„œ ๋‚˜์—๊ฒŒ ํ˜„์žฌ ํ•„์š”ํ•œ ๋…ธ๋“œ JS์˜ ๊ธฐ๋Šฅ์€ API ์„œ๋ฒ„๋ฅผ ๋งŒ๋“œ๋Š” ๊ฒƒ์œผ๋กœ, ์„œ๋ฒ„๋ฅผ ๋งŒ๋“ค๊ธฐ ์œ„ํ•œ ๊ธฐ์ดˆ API๋“ค์„ ๋จผ์ € ์ •๋ฆฌํ•˜๊ณ  ์„œ๋ฒ„๋ฅผ ๋งŒ๋“œ๋Š” ๊ณผ์ •์„ ์ •๋ฆฌํ•ด๋ณด๋ ค ํ•œ๋‹ค.

Module system

๋…ธ๋“œ์˜ ๋ชจ๋“ˆ์‹œ์Šคํ…œ์€ ์ž์ฒด์ ์ธ require(module)์ด๋ผ๋Š” ํ•จ์ˆ˜๋ฅผ ํ†ตํ•ด์„œ ๋ฐ›์•„์˜ฌ ์ˆ˜ ์žˆ๋‹ค. ํ˜„์žฌ๋Š” ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ์ž์ฒด์˜ import/export๋„ ์ด์šฉ๊ฐ€๋Šฅํ•œ๋ฐ, npm์˜ package.json์— "type":"module"๋กœ ์ถ”๊ฐ€ํ•ด์ฃผ์–ด์•ผํ•œ๋‹ค.

Path

๋ง๊ทธ๋Œ€๋กœ ๊ฒฝ๋กœ๋ฅผ ๋ฐ›์•„์˜ฌ ์ˆ˜ ์žˆ๋Š” ๋ชจ๋“ˆ๋กœ, ๋‹ค์–‘ํ•œ ๋””๋ ‰ํ† ๋ฆฌ, ํŒŒ์ผ ๋“ฑ์„ ๋ฐ›์•„์˜ฌ ์ˆ˜ ์žˆ๋Š” API์ด๋‹ค.

path.basename(__filename) //ํ˜„์žฌ ํŒŒ์ผ์˜ ๊ฒฝ๋กœ
path.extname(__filename) //ํ˜„์žฌํŒŒ์ผ์˜ ํ™•์žฅ์ž
path.join(__dirname, "image") //ํ˜„์žฌํด๋”์— image ํŒŒ์ผ์˜ ๊ฒฝ๋กœ

File system

ํŒŒ์ผ ์‹œ์Šคํ…œ ๋ชจ๋“ˆ์€ ํŒŒ์ผ, ํด๋”๋ฅผ ์ฝ๊ณ  ์“ฐ๊ณ  ์ด๋™ํ•˜๋Š” ๋“ฑ์˜ ์ผ์„ ํ•  ์ˆ˜ ์žˆ๋Š” api๋กœ script๋กœ ์ž‘์„ฑ์‹œ ์ž๋™ํ™” ํ”„๋กœ๊ทธ๋žจ๋„ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋‹ค.

์„œ๋ฒ„๋ฅผ ๋งŒ๋“ค๊ณ  ๋‚˜์„œ ๋‚ด ์ปดํ“จํ„ฐ ๋‚ด์˜ ํŒŒ์ผ๋“ค์„ ์ •๋ฆฌํ•˜๋Š” ์Šคํฌ๋ฆฝํŠธ๋ฅผ ๋งŒ๋“œ๋Š” ์—ฐ์Šต๋„ ํ•ด๋ณด๋ฉด ์ข‹์„ ๊ฒƒ ๊ฐ™๋‹ค.

fs.renameSync(oldPath,newPath) //๋™๊ธฐ์ ์œผ๋กœ ํŒŒ์ผ์„ ์ด๋™์‹œ์ผœ
fs.rename(oldPath,newPath,(error,data)=>{...}) //๋น„๋™๊ธฐ์ ์œผ๋กœ ํŒŒ์ผ์„ ์ด๋™์‹œ์ผœ
fs.promises // promise๋ฅผ ์ด์šฉํ•ด ๋น„๋™๊ธฐ์ ์œผ๋กœ ํŒŒ์ผ ์‹œ์Šคํ…œ์„ ์ž‘์„ฑ

fs.readFile(file, option)//๋น„๋™๊ธฐ์ ์œผ๋กœ option์œผ๋กœ ์ธ์ฝ”๋”ฉ๋ฐฉ์‹ ๋“ฑ์„ ์ •ํ•ด์„œ ํŒŒ์ผ์„ ์ฝ์–ด
fs.writeFile(file, data) //๋น„๋™๊ธฐ์ ์œผ๋กœ ํ•ด๋‹น ํŒŒ์ผ์— ๋ฐ์ดํ„ฐ๋ฅผ ์ƒˆ๋กœ ์ž‘์„ฑํ•œ๋‹ค
fs.appendFile(file, data) //๋น„๋™๊ธฐ์ ์œผ๋กœ ํ•ด๋‹น ํŒŒ์ผ์— ๋ฐ์ดํ„ฐ๋ฅผ ์ถ”๊ฐ€ ์ž‘์„ฑํ•œ๋‹ค

๋ฒ„ํผ์™€ ์ŠคํŠธ๋ฆผ

๋ฒ„ํผ์™€ ์ŠคํŠธ๋ฆผ์€ ๋„ˆ๋ฌด๋‚˜๋„ ์ต์ˆ™ํ•˜๊ฒŒ ๋งŽ์ด ๋“ค์–ด์˜จ ๊ฐœ๋…๋“ค์ด๋‹ค. ๋ฒ„ํผ๋Š” ๋ฐ์ดํ„ฐ ์กฐ๊ฐ์œผ๋กœ ์›๋ณธ ๋ฐ์ดํ„ฐ๋ฅผ ํ•œ๋ฒˆ์— ๋‹ค ๋ณด๋‚ด๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ ๋ฐ์ดํ„ฐ๋ฅผ ๋ฒ„ํผ๋กœ ์กฐ๊ธˆ์”ฉ ์ž˜๋ผ์„œ ๋ณด๋‚ธ๋‹ค. ์ด๋ ‡๊ฒŒ ๋ฐ์ดํ„ฐ ์กฐ๊ฐ์„ ๋ณด๋‚ด๋Š” ๊ณผ์ •์„ ์ŠคํŠธ๋ฆฌ๋ฐ์ด๋ผ๊ณ  ํ•˜๊ณ , ์‚ฌ์šฉ์ž๊ฐ€ ๋ฐ›๋Š” ๋ฐ์ดํ„ฐ์˜ ์†๋„๊ฐ€ ๋ณด๋‚ด๋Š” ๋ฐ์ดํ„ฐ ์†๋„๋ณด๋‹ค ๋น ๋ฅด๋‹ค๋ฉด, ํ™”๋ฉด์ด ๋ณด์ด์ง€ ์•Š๋Š” ๋“ฑ์˜ ์ผ์ด ์ผ์–ด๋‚˜๋Š”๋ฐ ์ด๋Ÿฐ ํ˜„์ƒ์„ ์šฐ๋ฆฌ๊ฐ€ ํ”ํžˆ ์ด์•ผ๊ธฐํ•˜๋Š” ๋ฒ„ํผ๋ง์ด ๊ฑธ๋ฆฐ๋‹ค๋Š” ์ผ์ด๋‹ค.

์ด๋ ‡๊ฒŒ ๋ฒ„ํผ์™€ ์ŠคํŠธ๋ฆผ์„ ์ด์šฉํ•˜๋ฉด ํ•œ๋ฒˆ์— ๋‹ค ๋ณด๋‚ด์„œ, ๋‹ค ๋ฐ›์„๋•Œ๊นŒ์ง€ ์‚ฌ์šฉ์ž๊ฐ€ ๋ณผ ์ˆ˜ ์—†๋Š” ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ์–ด์„œ ๋ฉ”๋ชจ๋ฆฌํšจ์œจ๊ณผ ์‹œ๊ฐ„ ํšจ์œจ์ด ์ข‹์€ ์žฅ์ ์„ ๊ฐ€์ง„๋‹ค.

[์‚ฌ์ง„ ์ถœ์ฒ˜: ์นด๋ ˆ์œ  ํ‹ฐ์Šคํ† ๋ฆฌ ]

buffer
buffer

const buf = Buffer.from("hello") //<Buffer 68 65 6c 6c 6f>
const buf2 = Buffer.from("hello") //<Buffer 68 65 6c 6c 6f>
const newBuf = Buffer.concat([buf, buf2]) //<Buffer 68 65 6c 6c 6f 68 65 6c 6c 6f> ๋ฒ„ํผ ์ด์–ด๋ถ™์ด๊ธฐ

const fs = require("fs")

const data = []

const readStream = fs
  .createReadStream(ํŒŒ์ผ, option)
  .on("data", chunk => {
    // ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ›์•„์˜ฌ ๋•Œ ๋งˆ๋‹ค ์‹คํ–‰ํ•ด
    data.push(chunk)
  })
  .on("end", () => {
    console.log(data.join("")) // ๋ฐ์ดํ„ฐ๋ฅผ ๋‹ค๋ฐ›์œผ๋ฉด ์‹คํ–‰ํ•ด
  })
  .on("error", error => console.log(error)) // ์—๋Ÿฌ ๋ฐœ์ƒ์‹œ ์‹คํ–‰ํ•ด

stream์„ ๊ณต๋ถ€ํ•˜๊ณ  ๋А๋‚€ ๊ฐ€์žฅ ํฐ ์žฅ์ ์€ piping์ด ๊ฐ€๋Šฅํ•˜๋‹ค๋Š” ์ ์ด๋‹ค. piping์€ stream๋“ค์„ ์ด์–ด์ฃผ๋Š” ๊ฒƒ์œผ๋กœ stream์˜ ๊ฒฐ๊ณผ๋“ค์„ chaining์ด ๊ฐ€๋Šฅํ•˜๋‹ค.

const readStream = fs.readStream("./ex1.txt")
const writeStream = fs.createWriteStream("./ex2.txt")
readSream.pipe(writeStream) //ex1.txt์„ ์ฝ๊ณ  ex2.txt์— ์“ฐ๋Š” ํŒŒ์ดํ”„

์„œ๋ฒ„ ์ œ์ž‘

์œ„์˜ ์ •๋ฆฌํ•œ Node JS API๋“ค๊ณผ HTTP ์ง€์‹๋“ค์„ ์ด์šฉํ•ด์„œ ๊ฐ„๋‹จํ•œ ์„œ๋ฒ„๋ฅผ ๋งŒ๋“ค์–ด๋ณด์•˜๋‹ค.

์„œ๋ฒ„์‚ฌ์ด๋“œ ๋ Œ๋”๋ง

Node ์„œ๋ฒ„๋Š” flask๋ฅผ ์‚ฌ์šฉํ–ˆ์„ ๋•Œ์™€ ๋™์ผํ•˜๊ฒŒ, request๋กœ ๋ฐ›์€ ์š”์ฒญ์— ๋”ฐ๋ผ response๋กœ ํ•ด๋‹นํ•˜๋Š” html์„ ๋ณด์—ฌ์ฃผ๋Š” ์„œ๋ฒ„๋ฅผ ๋จผ์ € ์ œ์ž‘ํ–ˆ๋‹ค. ๊ณผ์ •์€ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ •๋ฆฌํ•  ์ˆ˜ ์žˆ๋‹ค.

  1. http๋ชจ๋“ˆ์„ ์ด์šฉํ•ด์„œ ์„œ๋ฒ„๋ฅผ ๋งŒ๋“ ๋‹ค.
  2. ์„œ๋ฒ„์— ๋ฐ›์€ request์˜ url์— ๋”ฐ๋ผ html์„ ๋ณด๋‚ธ๋‹ค.

file์„ ์ฝ๋Š” ๋ฐฉ๋ฒ•์œผ๋กœ fs.readFile์œผ๋กœ ํ•  ์ˆ˜๋„ ์žˆ์ง€๋งŒ buffer์™€ stream์˜ ํšจ์œจ์ด ๋” ์ข‹๊ธฐ ๋•Œ๋ฌธ์— createReadStream์„ ์ด์šฉํ–ˆ๋‹ค.

stream์œผ๋กœ ๋ฐ›์•„์˜จ buffer ๋ฐ์ดํ„ฐ๋ฅผ pipe๋ฅผ ์ด์šฉํ•ด์„œ response๋กœ ๋ณด๋‚ด๋ฉด, res.end()๋ฅผ ํ•˜์ง€ ์•Š์•„๋„ ๋ฐ์ดํ„ฐ๊ฐ€ ๋‹ค ๋ฐ›์•„์ง€๋ฉด

pipe๊ฐ€ ์ž๋™์œผ๋กœ ๋๋‚ด์ค˜์„œ ์ฝ”๋“œ๊ฐ€ ๋” ๊ฐ„๋‹จํ•ด์ง„๋‹ค.

const http = require("http")
const fs = require("fs")
const path = require("path")

const server = http.createServer((req, res) => {
  const url = req.url
  const filePath = path.join(__dirname)
  res.setHeader("content-Type", "text/html") //์–ด๋–ค ํ˜•์‹์œผ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ๋ณด๋‚ผ์ง€๋ฅผ ๋‹ด์•„
  if (url === "/") {
    fs.createReadStream(`${filePath}/template/index.html`).pipe(res) //html์„ ๋ฒ„ํผ๋กœ ์ฝ์–ด์„œ ์ฝ์€ ๋ฐ์ดํ„ฐ๋ฅผ response๋กœ ํ˜๋ ค๋ณด๋‚ด์ค˜
  } else if (url === "/courses") {
    fs.createReadStream(`${filePath}/template/courses.html`).pipe(res)
  } else {
    fs.createReadStream(`${filePath}/template/not-found.html`).pipe(res)
  }
})

server.listen(8080)

JSON์„ ์ด์šฉํ•œ ์„œ๋ฒ„

JSON์€ Javascript Object Notation์˜ ์•ฝ์ž๋กœ ๋„คํŠธ์›Œํฌํ†ต์‹ ์„ ์œ„ํ•œ ๊ตฌ์กฐํ™”๋œ ๋ฐ์ดํ„ฐ๋ฅผ ์˜๋ฏธํ•œ๋‹ค. ์•ž์„œ ์ •๋ฆฌํ–ˆ์—ˆ๋˜ HTTP ํ†ต์‹ ์œผ๋กœ ๋ฐ›์€ request์— ๋”ฐ๋ผ ํ•ด๋‹นํ•˜๋Š” ์‘๋‹ต์„ ๋ณด๋‚ด์ค„๋•Œ, ์š”์ฒญ์—์„œ ์š”๊ตฌํ•˜๋Š” ๋ฐ์ดํ„ฐ๋ฅผ body์— ๋‹ด์•„์„œ ๋ณด๋‚ด์ค„ ๋•Œ, JSON์œผ๋กœ ์ „๋‹ฌํ•  ์ˆ˜ ์žˆ๋‹ค. ๊ฐ„๋‹จํ•˜๊ฒŒ ๋ฐฐ์—ด์„ GET์ด๋‚˜ POST๋ฅผ ์ด์šฉํ•ด์„œ JSON์œผ๋กœ ๋ณด๋‚ด์ฃผ๋Š” ์„œ๋ฒ„๋ฅผ ๋งŒ๋“ค์—ˆ๋‹ค. ์œ„์˜ ์„œ๋ฒ„์™€ ๋‹ค๋ฅด๊ฒŒ request์˜ method๋ณ„๋กœ ๋‹ค๋ฅธ ์‘๋‹ต์„ ๋ณด๋‚ด์ฃผ์–ด์•ผํ•˜๊ณ , ์ ์ ˆํ•œ status_code๋ฅผ ํ•จ๊ป˜ ๋‹ด์•„์ฃผ์–ด์•ผํ•œ๋‹ค.

(GET์ด ์„ฑ๊ณตํ•˜๋ฉด 200, POST๊ฐ€ ์„ฑ๊ณตํ•˜๋ฉด 201)

const arr = [1, 2, 3]

const server = http.createServer((req, res) => {
  const method = req.method
  if (method === "GET") {
    res.writeHead(200, { "Content-Type": "application/json" }) //head์— status_code, content-type์„ ๋‹ด์•„
    res.end(JSON.stringify(arr)) //์›ํ•˜๋Š”๊ฑธ ๋‹ด์•„์„œ ๋ณด๋‚ด์ค˜
  } else if (method === "POST") {
    const body = []
    req.on("data", chunk => {
      body.push(chunk)
    }) //req๋กœ ์˜จ ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ›์•„
    req.on("end", () => {
      const item = Buffer.concat(body).toString() //๋ฒ„ํผ๋กœ ๋ฐ›์•„์˜จ ๋ฐ์ดํ„ฐ๋ฅผ ์ด์–ด
      arr.push(JSON.parse(item))
      res.writeHead(201)
      res.end() //์•„๋ฌด๊ฒƒ๋„ ๋‹ด์ง€ ์•Š์•„
    })
  }
})

server.listen(8080)
@choi2021
๋งค์ผ์˜ ์‹œํ–‰์ฐฉ์˜ค๋ฅผ ๊ธฐ๋กํ•˜๋Š” ๊ฐœ๋ฐœ์ผ์ง€์ž…๋‹ˆ๋‹ค.