DAILY DOCDAILY DOC
Rust
Node
Notes
Ubuntu
Leetcode
  • it-tools
  • excalidraw
  • linux-command
Rust
Node
Notes
Ubuntu
Leetcode
  • it-tools
  • excalidraw
  • linux-command
  • node

    • NODE
    • parseArgs
    • compose
    • date-format
    • dayjs
    • encrypt
    • env-cmd
    • glob
    • Koa 洋葱模型
    • lodash
    • logger
    • log4js
    • mongod
    • nanoid
    • node-red
    • node-stream
    • node:test
    • nodemailer
    • nodemon
    • nodered
    • parse-curl
    • pm2
    • toml
    • ws
    • yargs
    • zx

Koa 洋葱模型

Koa Http Server

const Koa = require('koa');
const app = new Koa();

app.use(async ctx => {
  ctx.body = 'Hello World';
});

app.listen(3000);

Node Http Server

const http = require("http");
const server = http.createServer((req, res) => {
    const stream = fs.createReadStream('file.txt');
    stream.on('data', (chunk) => {
        res.write(chunk); // Write data to the response
    });
    stream.on('end', () => {
        res.end(); // End the response
    });
});

server.listen(3003, () => {
  console.log("Server running at localhost:3003");
});

洋葱模型实现

  1. app.use

class 初始化一个 middleware 数组,use 的时候把function push到队列

use(fn) {
 this.middleware.push(fn);
 return this;
}

2.app.listen

node http 模块创建一个HttpServer,传入相应的 callback

  listen(...args) {
    const server = http.createServer(this.callback());
    return server.listen(...args);
  }
  // http.createServer((req,res) => {}) 接受2个参数,req, res
  1. HttpServer callback函数 callback实现
  callback() {
    // 重点是 compose 函数实现
    const fn = compose(this.middleware);

    // 此处返回一个 callback 接受 req,res 2个参数
    const handleRequest = (req, res) => {
      //  创建 middleware context 
      const ctx = this.createContext(req, res);

      return this.handleRequest(ctx, fn);
    };

    return handleRequest;
  }
  1. compose

function compose (middleware) { 
  if (!Array.isArray(middleware)) throw new TypeError('Middleware stack must be an array!')
  for (const fn of middleware) {
    if (typeof fn !== 'function') throw new TypeError('Middleware must be composed of functions!')
  }
  return function (context, next) {
    // last called middleware #
    let index = -1
    return dispatch(0)

    function dispatch (i) {
      if (i <= index) return Promise.reject(new Error('next() called multiple times'))
      index = i
      let fn = middleware[i]
      if (i === middleware.length) fn = next
      if (!fn) return Promise.resolve()
      try {
        return Promise.resolve(fn(context, dispatch.bind(null, i + 1)));
      } catch (err) {
        return Promise.reject(err)
      }
    }
  }
}

  1. handleRequest
  handleRequest(ctx, fnMiddleware) {
    // promise 
    return fnMiddleware(ctx)
      .then(handleResponse)
      .catch(onerror);
  }
  1. respond
Javascript
    const stream = fs.createReadStream('file.txt');
    stream.on('data', (chunk) => {
        res.write(chunk); // Write data to the response
    });
    stream.on('end', () => {
        res.end(); // End the response
    });

    // 等价于
    const stream = fs.createReadStream('file.txt');
    stream.pipe(res)

koa 中对 ctx.body 类型做了判断,stream 类型流式返回

alt text

Javascript
    const stream = fs.createReadStream('file.txt');
    stream.on('data', (chunk) => {
        res.write(chunk); // Write data to the response
    });
    stream.on('end', () => {
        res.end(); // End the response
    });
Koa 源码
class Koa extends Emitter {
    constructor (options) {
      this.middleware = []
    }
    use (fn) {
      this.middleware.push(fn)
      return this
    }
    callback () {
      const fn = compose(this.middleware)
      if (!this.listenerCount('error')) this.on('error', this.onerror)

      const handleRequest = (req, res) => {
        const ctx = this.createContext(req, res)
        return this.handleRequest(ctx, fn)
      }

      return handleRequest
    }
    listen (...args) {
      const server = http.createServer(this.callback())
      return server.listen(...args)
    }
    handleRequest (ctx, fnMiddleware) {
      const res = ctx.res
      res.statusCode = 404
      const onerror = err => ctx.onerror(err)
      const handleResponse = () => respond(ctx)
      onFinished(res, onerror)
      return fnMiddleware(ctx).then(handleResponse).catch(onerror)
    }
}
Koa compose实现
function compose (middleware) {
  if (!Array.isArray(middleware)) throw new TypeError('Middleware stack must be an array!')
  for (const fn of middleware) {
    if (typeof fn !== 'function') throw new TypeError('Middleware must be composed of functions!')
  }

  /**
   * @param {Object} context
   * @return {Promise}
   * @api public
   */

  return function (context, next) {
    // last called middleware #
    let index = -1
    return dispatch(0)
    function dispatch (i) {
      if (i <= index) return Promise.reject(new Error('next() called multiple times'))
      index = i
      let fn = middleware[i]
      if (i === middleware.length) fn = next
      if (!fn) return Promise.resolve()
      try {
        return Promise.resolve(fn(context, dispatch.bind(null, i + 1)));
      } catch (err) {
        return Promise.reject(err)
      }
    }
  }
}

Last Updated:
Contributors: rosendo
Prev
glob
Next
lodash