๐ŸŒณ๋ชฉํ‘œ

Middleware ๋ชจ๋“ˆ์„ ํ™œ์šฉํ•˜์—ฌ serve-static์˜ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•ฉ๋‹ˆ๋‹ค. ๊ธฐ์กด ์ฝ”๋“œ๋„ ๋ฏธ๋“ค์›จ์–ด ํ˜•ํƒœ๋กœ ๊ฐœ์„ ํ•ฉ๋‹ˆ๋‹ค.

Middleware๋กœ Application.use() ๋ฉ”์†Œ๋“œ ๊ตฌํ˜„

์ด์ „ ์‹œ๊ฐ„๊นŒ์ง€ ์ž‘์„ฑํ•œ ์ฝ”๋“œ๋กœ ์ฒดํฌ์•„์›ƒ ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

$ git checkout -f application/use-spec

์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ ๋ฏธ๋“ค์›จ์–ด ํ•จ์ˆ˜๋ฅผ ๋“ฑ๋กํ•ด์•ผ ํ•˜๋Š”๋ฐ์š” Application.use() ๋ฉ”์†Œ๋“œ๊ฐ€ ๊ทธ ์—ญํ• ์„ ํ•˜๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค. ์ด ๋ฉ”์†Œ๋“œ๋Š” ๋‚ด๋ถ€์ ์œผ๋กœ ๋ฏธ๋“ค์›จ์–ด์˜ add() ๋ฉ”์†Œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜๊ฒ ์ฃ ?

์ข€ ๋” ์ž์„ธํžˆ ๋ณด๊ธฐ ์œ„ํ•ด ํ…Œ์ŠคํŠธ ํŒŒ์ผ์„ ์‚ดํŽด ๋ณด์ง€์š”.

src/Application.spec.js ํŒŒ์ผ์„ ๋ด…๋‹ˆ๋‹ค.

  describe('use()', () => {
    it('Middleware ๋ชจ๋“ˆ ์ธ์Šคํ„ด์Šค์˜ add() ๋ฉ”์†Œ๋“œ๋ฅผ ์‹คํ–‰ํ•œ๋‹ค', () => {
      const spy = sinon.spy();
      app._middleware.add = spy;
      const mw1 = () => null;

      app.use(mw1);

      should(spy.called).be.equal(true);
    })
  })

use() ๋ฉ”์†Œ๋“œ๋Š” โ€œMiddleware์˜ add() ๋ฉ”์†Œ๋“œ๋ฅผ ์‹คํ–‰ํ•œ๋‹คโ€๋Š” ํ…Œ์ŠคํŠธ ์ผ€์ด์Šค ์ž…๋‹ˆ๋‹ค. ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋‚ด๋ถ€ ๋ณ€์ˆ˜์ธ _middleware์˜ add์— ์ŠคํŒŒ์ด๋ฅผ ์‹ฌ์—ˆ์Šต๋‹ˆ๋‹ค.

๊ทธ๋ฆฌ๊ณ  app.use()๋ฅผ ์‹คํ–‰ํ•œ ๊ฒฐ๊ณผ ์ด ์ŠคํŒŒ์ด ํ•จ์ˆ˜๊ฐ€ ์‹คํ–‰๋˜๋Š”์ง€ ์ ๊ฒ€ํ•˜๋Š” ๊ฒƒ์ด์ฃ .

src/Application.js ํŒŒ์ผ์„ ์ˆ˜์ •ํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. ์„ธ ๋ถ€๋ถ„์œผ๋กœ ๋‚˜๋ˆ  ์ง„ํ–‰ํ•ฉ๋‹ˆ๋‹ค.

const Middleware = require('./Middleware');

const Application = () => {
  const _middleware = Middleware();

Middleware ๋ชจ๋“ˆ์„ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  Application ํด๋กœ์ ธ ๋ณ€์ˆ˜์— Middleware ์ธ์Šคํ„ด์Šค๋ฅผ ํ•˜๋‚˜ ๋งŒ๋“ค์—ˆ์Šต๋‹ˆ๋‹ค. ์ด ์ฝ”๋“œ๋Š” ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์ด ๊ตฌ๋™๋˜๋Š” ๋™์•ˆ ๋”ฑ ํ•œ ๋ฒˆ๋งŒ ์‹คํ–‰ ๋˜๊ฒ ์ฃ ?

  const _server = http.createServer((req, res) => {
    _middleware.run(req, res);
   });

  const use = fn => _middleware.add(fn);

ํ•จ์ˆ˜ํƒ€์ž… fn๋ฅผ ์ธ์ž๋กœ ๋ฐ›๋Š” use() ๋ฉ”์†Œ๋“œ ์ž…๋‹ˆ๋‹ค. ํด๋กœ์ ธ ๋ณ€์ˆ˜ _middleware์˜ add ํ•จ์ˆ˜๋ฅผ ์‹คํ–‰ํ•ด์„œ ์ธ์ž๋กœ ๋ฐ›์€ ํ•จ์ˆ˜๋ฅผ ๋ฏธ๋“ค์›จ์–ด ๋ฐฐ์—ด์— ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.

๊ทธ๋ฆฌ๊ณ  ์š”์ฒญ์ด ์˜ฌ๋•Œ๋งˆ๋‹ค _middleware.run() ๋ฉ”์†Œ๋“œ๋ฅผ ์‹คํ–‰ํ•ด ๋ชจ๋“  ๋ฏธ๋“ค์›จ์–ด ํ•จ์ˆ˜๋ฅผ ์‹คํ–‰์‹œํ‚ต๋‹ˆ๋‹ค.

   return {
     _milldeware, // ํ…Œ์ŠคํŠธ์šฉ 
     _server,
     use, // use ๋…ธ์ถœ 
     listen
   }

๋งˆ์ง€๋ง‰์œผ๋กœ ํด๋กœ์ ธ ๋ณ€์ˆ˜์™€ use ๋ฉ”์†Œ๋“œ๋ฅผ ๋…ธ์ถœํ•ด์„œ ์™ธ๋ถ€์—์„œ ์‚ฌ์šฉํ•˜๋„๋ก ์ฒ˜๋ฆฌํ•ฉ๋‹ˆ๋‹ค.

์—ฌ๊ธฐ๊นŒ์ง€๊ฐ€ ๋ฏธ๋“ค์›จ์–ด๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•œ ์ค€๋น„ ์ž‘์—…์ด์—ˆ์Šต๋‹ˆ๋‹ค.

๋“œ๋””์–ด ์ต์Šคํ”„๋ ˆ์ŠคJS์˜ ๋‘ ๋ฒˆ์งธ ๋ชจ๋“ˆ(์ดˆ๋ก์ƒ‰)์„ ๊ตฌํ˜„ํ•œ ๊ฒƒ์ด์ฃ .

๐Ÿค์‹ค์Šต - serve-static ๋ฏธ๋“ค์›จ์–ด๋กœ ๋ณ€๊ฒฝ

src/serve-static.js๋ฅผ middlewares/serve-static.js ํŒŒ์ผ๋กœ ์˜ฎ๊ฒจ ๋ฏธ๋“ค์›จ์–ด ํ•จ์ˆ˜ ํ˜•ํƒœ๋กœ ๊ตฌํ˜„ํ•˜์„ธ์š”.

๋ฐฉ๊ธˆ๊นŒ์ง€ ์ž‘์„ฑํ•œ ์ฝ”๋“œ๋กœ ๋ธŒ๋žœ์น˜๋ฅผ ์ด๋™ํ•ฉ๋‹ˆ๋‹ค.

$ git checkout -f application/use

ํžŒํŠธ: ๋ฏธ๋“ค์›จ์–ด ํ•จ์ˆ˜ ์ธํ„ฐํŽ˜์ด์Šค๋Š” (req, res, next) => { / โ€ฆ /}

๐Ÿคํ’€์ด

๊ทธ๋Ÿผ ํ•จ๊ป˜ ํ’€์–ด ๋ณผ๊นŒ์š”?

middlewares/serve-static.js ํŒŒ์ผ์„ ๋งŒ๋“ค์–ด ๊ธฐ์กด ์ฝ”๋“œ๋ฅผ ์˜ฎ๊น๋‹ˆ๋‹ค.

const path = require('path')
// ...

const serveStatic = () => (req, res, next) => { // ๋ฏธ๋“ค์›จ์–ด ํ•จ์ˆ˜ ์ธํ„ฐํŽ˜์ด์Šค
   const mimeType = {
     '.ico': 'image/x-icon',
    // ...
    if (Object.keys(mimeType).includes(ext)) {
      // ...
    } else {
      next() // ๋‹ค์Œ ๋ฏธ๋“ค์›จ์–ด๋ฅผ ์ˆ˜ํ–‰
    }
 }

module.exports = serveStatic;

๋ฏธ๋“ค์›จ์–ด ํ•จ์ˆ˜๋Š” ์„ธ ๊ฐœ ์ธ์ž๋ฅผ ๋ฐ›๊ธฐ ๋•Œ๋ฌธ์— (req, res, next)๋กœ ํ•จ์ˆ˜ ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๋ณ€๊ฒฝํ•ฉ๋‹ˆ๋‹ค.

์ด์ „๊ณผ๋Š” ๋‹ฌ๋ฆฌ ์ด์ œ๋Š” if/else๋กœ ๋น„๋™๊ธฐ ๋กœ์ง์„ ์ œ์–ดํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. mimeType ๋”•์…”๋„ˆ๋ฆฌ์— ์žˆ์„ ๊ฒฝ์šฐ์—๋Š”(if) ๊ธฐ์กด์ฒ˜๋Ÿผ ์‘๋‹ตํ•˜๊ณ , ๊ทธ๋ ‡์ง€ ์•Š์„ ๊ฒฝ์šฐ(else) ๋‹ค์Œ ๋ฏธ๋“ค์›จ์–ด๋ฅผ ํ˜ธ์ถœ(next()) ํ•ฉ๋‹ˆ๋‹ค.

app.js๋Š” ์–ด๋–ป๊ฒŒ ๋‹ฌ๋ผ ์งˆ๊นŒ์š”?

const app = App()
const serveStatic = require('./middlewares/serve-static')

app.use(serveStatic())

use() ๋ฉ”์†Œ๋“œ๋กœ ๋ฏธ๋“ค์›จ์–ด ํ•จ์ˆ˜๋ฅผ ๊ฐ„๋‹จํžˆ ๋“ฑ๋กํ–ˆ์Šต๋‹ˆ๋‹ค. ์ต์Šคํ”„๋ ˆ์Šค์˜ ๊ทธ๊ฒƒ๊ณผ ๋งค์šฐ ๋น„์Šทํ•˜๋„ค์š”.

์จ๋“œ ํŒŒํ‹ฐ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋กœ serve-static์ด ์ถ”๊ฐ€๋œ๊ฒƒ์„ ํ™•์ธํ• ์ˆ˜ ์žˆ๊ฒ ์ฃ ?

๋‚˜๋จธ์ง€๋„ ๋ฏธ๋“ค์›จ์–ด ํ•จ์ˆ˜๋กœ ์ถ”๊ฐ€

index.html๋ฅผ ์ฒ˜๋ฆฌํ•˜๋Š” ๋ถ€๋ถ„๋„ ๋ฏธ๋“ค์›จ์–ด ํ•จ์ˆ˜๋กœ ๋งŒ๋“ค์–ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. app.js์—์„œ ๋ฐ”๋กœ ์ฝ”๋”ฉํ• ๊ฒŒ์š”.

// ...
const app = App();
const path = require('path')
const fs = require('fs')

const index = (req, res, next) => {
  const publicPath = path.join(__dirname, './public')

  fs.readFile(`${publicPath}/index.html`, (err, data) => {
    if (err) throw err

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

app.use(serveStatic());
app.use(index);

์—๋Ÿฌ ์ฒ˜๋ฆฌ ๋ฏธ๋“ค์›จ์–ด๋„ ์ถ”๊ฐ€ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

const error404 = (req, res, next) => {
  res.statusCode = 404
  res.end('Not Found')
}

const error = (err, req, res, next) => {
  res.statusCode = 500
  res.end()
}

app.use(serveStatic())
app.use(index)
app.use(error404)
app.use(error)

์ •๋ฆฌ

  • ๋ฏธ๋“ค์›จ์–ด๋ฅผ ์ด์šฉํ•ด์„œ serve-static๊ณผ ๊ธฐ๋ณธ์ ์ธ ๋ผ์šฐํŒ…์„ ๊ตฌํ˜„ํ–ˆ์Šต๋‹ˆ๋‹ค.

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