๐ŸŒณ๋ชฉํ‘œ

์„œ๋ฒ„์— ์ž์› ์ค‘์—์„œ ๋ธŒ๋ผ์šฐ์ ธ์— ๋‹ค์šด๋กœ๋“œํ•˜์—ฌ ํ™”๋ฉด์„ ๊ทธ๋ฆฌ๋Š” ํŒŒ์ผ์„ ์ •์ ํŒŒ์ผ์ด๋ผ๊ณ  ํ•ฉ๋‹ˆ๋‹ค. ์ด๋ฒˆ์— ์ด ๊ธฐ๋Šฅ์„ ๋งŒ๋“ค์–ด ๋ด…๋‹ˆ๋‹ค.

์ •์  ํŒŒ์ผ์ด๋ž€?

๋ฏธ๋ฆฌ ๋งŒ๋“ค์–ด๋‘” ๋ธŒ๋žœ์น˜๋กœ ์ด๋™ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

$ git checkout -f module/static-files

public ํด๋”๊ฐ€ ๋ณด์ด์ฃ ? ์ด๊ณณ์— ๋ชจ๋“  ์ •์ ํŒŒ์ผ์„ ๋ชจ์•„๋‘์—ˆ์Šต๋‹ˆ๋‹ค.

$ tree public

public
โ”œโ”€โ”€ css
โ”‚   โ””โ”€โ”€ style.css
โ”œโ”€โ”€ imgs
โ”‚   โ””โ”€โ”€ twitter.png
โ”œโ”€โ”€ index.html
โ””โ”€โ”€ js
    โ””โ”€โ”€ script.js

์ด ํŒŒ์ผ์„ ๋ธŒ๋ผ์šฐ์ €์—์„œ ์š”์ฒญ์„ ํ•˜๋ฉด ์„œ๋ฒ„์—์„œ๋Š” ๋‹ค์šด๋กœ๋“œ ํ• ์ˆ˜ ์žˆ๋„๋ก ์ฒ˜๋ฆฌํ•ด ์ฃผ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

๐Ÿค์‹ค์Šต - ์ •์  ํŒŒ์ผ ์š”์ฒญ์— ์‘๋‹ตํ•˜๋Š” ๊ธฐ๋Šฅ ๊ตฌํ˜„ 1

ํด๋ผ์ด์–ธํŠธ ์š”์ฒญ์‹œ โ€œHello worldโ€ ๋ฌธ์ž์—ด ๋Œ€์‹  public/index.html ํŒŒ์ผ์„ ์‘๋‹ตํ•˜๋Š” ๊ธฐ๋Šฅ์„ ๊ตฌํ˜„ํ•˜์„ธ์š”.

ํžŒํŠธ: file system ๊ธฐ๋ณธ ๋ชจ๋“ˆ๋กœ ํŒŒ์ผ์„ ์ฝ๊ณ  ์‘๋‹ตํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๐Ÿคํ’€์ด

fs (file system) ๋ชจ๋“ˆ์„ ์ฒ˜์Œ ์จ ๋ณด๋Š”๋ฐ์š”, ์‰ฝ๊ฒŒ ํ•ด๊ฒฐํ•˜์…จ๋‚˜์š”? ๊ทธ๋Ÿผ ๊ฐ™์ด ํ’€์–ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

๊ธฐ์กด์— โ€œHello worldโ€๋ฅผ ์‘๋‹ตํ•˜๋Š” ์ฝ”๋“œ๋Š” src/Application.js์— ์žˆ์—ˆ์ฃ ? ์ด ํŒŒ์ผ์„ ์ˆ˜์ •ํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

const path = require('path')
const fs = require('fs')

const Application = () => {
  const server = http.createServer((req, res) => {
    // ...

    const filePath = path.join(__dirname, '../public/index.html') 
    fs.readFile(filePath, (err, data) => {
      if (err) throw err
      
      res.end(data)
    })
  });
}

path ๋ชจ๋“ˆ์˜ join์„ ์ด์šฉํ•ด์„œ ํ˜„์žฌ๊ฒฝ๋กœ(__dirname)์™€ ํŒŒ์ผ์ด ์œ„์น˜ํ•œ ์ƒ๋Œ€ ๊ฒฝ๋กœ(../public/index.html)์„ ๊ณ„์‚ฐํ•ฉ๋‹ˆ๋‹ค. filePath์—๋Š” index.html์˜ ์ ˆ๋Œ€ ๊ฒฝ๋กœ๊ฐ€ ์ €์žฅ ๋˜๊ฒ ์ง€์š”.

๊ทธ๋ฆฌ๊ณ  ๋‚˜์„œ fs ๋ชจ๋“ˆ์˜ readFile ํ•จ์ˆ˜๋กœ ๊ฒฝ๋กœ์˜ ํŒŒ์ผ์„ ์ฝ์Šต๋‹ˆ๋‹ค. ์—๋Ÿฌ๋ฅผ ํ™•์ธ ํ•œ๋’ค ์ •์ƒ์ด๋ฉด data์— ํŒŒ์ผ ๋‚ด์šฉ์ด ๋ฌธ์ž์—ด๋กœ ๋“ค์–ด์˜จ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๋งˆ์ง€๋ง‰์— res.end() ํ•จ์ˆ˜๋กœ ํŒŒ์ผ ๋‚ด์šฉ์„ ์‘๋‹ตํ•ด ์ฃผ๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

์ €์žฅํ•˜๊ณ  ํ•œ๋ฒˆ ๋ธŒ๋ผ์šฐ์ ธ์—์„œ ํ™•์ธํ•ด ๋ณผ๊นŒ์š”?

HTML ๋งˆํฌ์—…์ด ๊ทธ๋Œ€๋กœ ์ถœ๋ ฅ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ์šฐ๋ฆฌ๊ฐ€ ์›ํ•˜๋Š”๊ฑด ์›นํŽ˜์ด์ง€๋กœ ๋ Œ๋”๋ง ๋˜๋Š”๊ฑด๋ฐ ๋ง์ด์ฃ .

์ด ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๋ ค๋ฉด HTTP ํ—ค๋”๊ฐ’ ์ค‘ ํ•˜๋‚˜๋ฅผ ๋ณ€๊ฒฝํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

    res.statusCode = 200
    res.setHeader('Content-Type', 'text/html') 

ํŒŒ์ผ ๋‚ด์šฉ์„ ์‘๋‹ตํ•˜๊ธฐ ์ „์— Content-Type ํ—ค๋”๋ฅผ text/plain ์—์„œ text/html๋กœ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค.

์ €์žฅํ•˜๊ณ  ๋‹ค์‹œ ๋ธŒ๋ผ์šฐ์ ธ๋กœ ํ™•์ธํ•ด ๋ณผ๊นŒ์š”?

์ด์ œ์•ผ ์›นํŽ˜์ด์ง€์ฒ˜๋Ÿผ ๋‚˜์˜ค๋Š” ๊ฒƒ์„ ํ™•์ธํ–ˆ๋„ค์š”.

ํ•˜์ง€๋งŒ ์ด๋ฏธ์ง€ ๋ถ€๋ถ„์ด ๊นจ์ ธ์„œ ๋‚˜์˜ค๋Š”๋ฐ์š”? ํฌ๋กฌ ๊ฐœ๋ฐœ์ž ๋„๊ตฌ๋กœ ์ž์„ธํžˆ ์‚ดํŽด ๋ณผ๊นŒ์š”?

index.html์€ ๋‚ด๋ถ€ ์ฝ”๋“œ์—์„œ css, js, image ํŒŒ์ผ์„ ์ถ”๊ฐ€๋กœ ์š”์ฒญํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฐ๋ฐ ์ด ์š”์ฒญ์— ๋Œ€ํ•œ ์‘๋‹ต์ด ์ „๋ถ€ index.html ํŒŒ์ผ์˜ ๋‚ด์šฉ๊ณผ ๋˜‘๊ฐ™๋„ค์š”.

๊ทธ๋ ‡์Šต๋‹ˆ๋‹ค. Application์—์„œ ๋ชจ๋“  ์š”์ฒญ์— ๋Œ€ํ•ด index.html๋งŒ ์‘๋‹ตํ•˜๋„๋ก ์ฝ”๋”ฉํ–ˆ๊ธฐ ๋•Œ๋ฌธ์ด์—์š”.

๐Ÿค์‹ค์Šต - ์ •์  ํŒŒ์ผ ์š”์ฒญ์— ์‘๋‹ตํ•˜๋Š” ๊ธฐ๋Šฅ ๊ตฌํ˜„ 2

index.html์—์„œ ์ถ”๊ฐ€๋กœ ์š”์ฒญํ•˜๋Š” ์ •์  ๋ฆฌ์†Œ์Šค์ธ JS, CSS, IMAGE๋„ ์ œ๊ณตํ•˜๋Š” ๊ธฐ๋Šฅ์„ ๊ตฌํ˜„ํ•˜์„ธ์š”.

ํžŒํŠธ: mineType, content-type์œผ๋กœ ๊ฒ€์ƒ‰ํ•ด ๋ณด์„ธ์š”. req.url๋กœ ์š”์ฒญ ์ฃผ์†Œ์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. path.parse().ext๋กœ ํ™•์žฅ์ž๋ฅผ ์•Œ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๐Ÿคํ’€์ด

์ด๋ฒˆ๊ฑด ์กฐ๊ธˆ ์–ด๋ ค์› ์„ ์ˆ˜๋„ ์žˆ๊ฒŒ๋„ค์š”. ๊ทธ๋Ÿผ ๊ฐ™์ด ํ’€์–ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

const mimeType = {
  '.ico': 'image/x-icon',
  '.html': 'text/html',
  '.js': 'text/javascript',
  '.css': 'text/css',
  '.png': 'image/png',
  '.jpg': 'image/jpeg',
  '.eot': 'appliaction/vnd.ms-fontobject',
  '.ttf': 'aplication/font-sfnt'
}

๋จผ์ € mineType ๋”•์…”๋„ˆ๋ฆฌ๋ฅผ ๋งŒ๋“ค์–ด ํ™•์žฅ์ž ํ‚ค์— ๋งˆ์ž„ํƒ€์ž„ ๊ฐ’์„ ์‚ฌ์šฉํ–ˆ์Šต๋‹ˆ๋‹ค. ์š”์ฒญ ์ฃผ์†Œ๋ฅผ ํŒŒ์‹ฑํ•ด์„œ ํ™•์žฅ์ž์— ๋”ฐ๋ผ content-type ํ—ค๋” ๊ฐ’์„ ๋™์ ์œผ๋กœ ์„ค์ •ํ•˜๋ ค๊ณ  ํ•ฉ๋‹ˆ๋‹ค.

const ext = path.parse(req.url).ext;
const publicPath = path.join(__dirname, '../public')

req.url์„ ํ†ตํ•ด ์š”์ฒญ ์ฃผ์†Œ์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๊ฑธ path.parse() ํ•จ์ˆ˜์˜ ์ธ์ž๋กœ ๋„˜๊ธฐ๋ฉด ์ฃผ์†Œ๋ฅผ ํŒŒ์‹ฑํ•˜๋Š”๋ฐ ๊ทธ ๊ฒฐ๊ณผ ext ํ‚ค์— ํ™•์žฅ์ž ์ •๋ณด๊ฐ€ ๋‹ด๊ฒจ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๊ฒƒ์„ ext ์ƒ์ˆ˜์— ์ €์žฅํ–ˆ๊ตฌ์š”.

์ •์  ํŒŒ์ผ์€ ๋ชจ๋‘ public ํด๋”์— ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ์ ˆ๋Œ€ ๊ฒฝ๋กœ๋ฅผ ๊ณ„์‚ฐํ•ด์„œ publicPath ์ƒ์ˆ˜์— ์ €์žฅํ–ˆ์Šต๋‹ˆ๋‹ค.

if (Object.keys(mimeType).includes(ext)) {
  fs.readFile(`${publicPath}${req.url}`, (err, data) => {
    if (err) {
      res.statusCode = 404;
      res.end('Not found');
    } else {
      res.statusCode = 200
      res.setHeader('Content-Type', mimeType[ext]);
      res.end(data)
    })
  })
} else {
  res.statusCode = 200;
  // ...

์š”์ฒญํ•œ ํ™•์žฅ์ž๊ฐ€ mineType ๋”•์…”๋„ˆ๋ฆฌ์— ์žˆ์„ ๊ฒฝ์šฐ ์ฒซ๋ฒˆ์งธ if ๊ตฌ๋ฌธ์„ ์‹คํ–‰ํ•˜๊ฒ ์ฃ . publicPath์™€ req.url๋ฅผ ํ•ฉ์ณ ์ •์  ํŒŒ์ผ์„ ์ฝ์Šต๋‹ˆ๋‹ค. ๋งŒ์•ฝ ํŒŒ์ผ ์ฝ๊ธฐ์— ์‹คํŒจํ•œ๋‹ค๋ฉด(๊ฐ€๋ น ํŒŒ์ผ์ด ์—†์„ ๊ฒฝ์šฐ) Not found๋ฅผ ์˜๋ฏธํ•˜๋Š” 404๋ฅผ ์‘๋‹ตํ–ˆ๊ตฌ์š”, ํŒŒ์ผ์ด ์žˆ๋‹ค๋ฉด memeType[ext]๋กœ content-type ํ—ค๋” ๊ฐ’์„ ๋™์ ์œผ๋กœ ์•Œ์•„๋‚ด์„œ ์‘๋‹ตํ–ˆ์Šต๋‹ˆ๋‹ค.

์š”์ฒญํ•œ ํ™•์žฅ์ž๊ฐ€ mineType ๋”•์…”๋„ˆ๋ฆฌ์— ์—†๋‹ค๋ฉด ์ด์ „๊ณผ ๋™์ผํ•˜๊ฒŒ index.html์„ ์‘๋‹ตํ•˜๋„๋ก ํ–ˆ๊ตฌ์š”.

๊ทธ๋Ÿผ ์ €์žฅํ•˜๊ณ  ๋ธŒ๋ผ์šฐ์ ธ๋กœ ํ™•์ธํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

์ด์ œ์•ผ ๋น„๋กœ์†Œ ์›น ํŽ˜์ด์ง€๊ฐ€ ์ œ๋Œ€๋กœ ๋ณด์ด๋Š”๊ตฐ์š”.

์ •๋ฆฌ

  • HTML, CSS, JS, IMAGE ์ฒ˜๋Ÿผ ๋ธŒ๋ผ์šฐ์ ธ์—์„œ ๋ Œ๋”๋ง ๋˜๋Š” ์ž์›์„ ์ •์ ํŒŒ์ผ์ด๋ผ๊ณ  ํ•ฉ๋‹ˆ๋‹ค.
  • MineType์„ ์„ค์ •ํ•˜์—ฌ ์ •์  ํŒŒ์ผ ์ œ๊ณต ๊ธฐ๋Šฅ์„ ๊ตฌํ˜„ํ–ˆ์Šต๋‹ˆ๋‹ค.

๋ชฉ์ฐจ ๋ฐ”๋กœ๊ฐ€๊ธฐ