Preliminary knowledge

Getter /setter methods wrap access to data

const obj = {
    info : { name : "jason"},
    get name() {return this.info.name;
    },
    set name(val) {console.log("Start setting up new content",val)
        this.info.name = val
    }
}
console.log(obj.name)
obj.name = "xxx"
console.log(obj.name)
Copy the code

Koa framework implementation

Overall code structure

MyKoa source code implementation

// mykoa.js // main code
//context.js // Record context encapsulates req and res
//request.js // rewrite the original HTTP request object
//response.js // override the original HTTP response object
//app.js // program entry


//myKoa.js
const http = require("http")
const context = require('./context')
const request = require('./request')
const response = require('./response')

class myKoa {
    constructor(){
        this.middlewares = []
    }
    listen(. args){
        const server = http.createServer(async (req, res) => {

            // Create context
            const ctx = this.createCTX(req, res)
            const fn = this.compose(this.middlewares)
            await fn(ctx)
            // this.callback(req,res)
            // this.callback(ctx)res.end(ctx.body) }) server.listen(... args) }use(middleware){
        this.middlewares.push(middleware)
    }
    createCTX(req, res) {
        const ctx = Object.create(context)
        ctx.request = Object.create(request)
        ctx.response = Object.create(response)

        ctx.req = ctx.request.req = req
        ctx.res = ctx.response.res = res
        return ctx
    }
    compose(middlewares) {
        return function (ctx) {
            return dispatch(0)
            function dispatch(i) {
                let fn = middlewares[i]
                if(! fn) {return Promise.resolve()
                }
                return Promise.resolve(
                    fn(ctx, function next() {
                        return dispatch(i + 1)})}}}}module.exports = myKoa
 
//context.js
module.exports = {
    get url() {
        return this.request.url
    },
    get body() {
        return this.response.body
    },
    set body(val) {this.response.body = val
    },
    get method() {
        return this.request.method
    }
}

//request.js
module.exports ={
    get url() {return this.req.url
    },

    get method() {return this.req.method.toLowerCase()
    }
}

//response.js
module.exports = {
    get body() {return this._body
    },
    set body(val) {this._body = val
    }
}



// Application test entry app.js
const myKoa = require('./myKoa')
const app = new myKoa()
const delay = () = > Promise.resolve(resolve= > setTimeout(() = > resolve(), 2000));
app.use(async (ctx, next) => {
    ctx.body = "1";
    setTimeout(() = > {
        ctx.body += "2";
    }, 2000);
    await next();
    ctx.body += "3";
});

app.use(async (ctx, next) => {
    ctx.body += "4";
    await delay();
    await next();
    ctx.body += "5";
});

app.use(async (ctx, next) => {
    ctx.body += "6";
});
app.listen(3000)
Copy the code

Implementation of KOA-Router routing

  1. Use policy mode/decision mode, principle: registry matching read mode
  2. Save the global arraylist object stack object,
  3. Each registration record object route: request mode, address, corresponding method
  4. Each response matches the corresponding request mode and address, and executes the corresponding method
//router.js
class Router {
    constructor() {
      this.stack = [];
    }
  
    register(path, methods, middleware) {
      let route = {path, methods, middleware}
      this.stack.push(route);
    }
    // Now only get and POST are supported
    get(path,middleware){
      this.register(path, 'get', middleware);
    }
    post(path,middleware){
      this.register(path, 'post', middleware);
    }
    routes() {
      let stock = this.stack;
      return async function(ctx, next) {
        let currentPath = ctx.url;
        let route;
  
        for (let i = 0; i < stock.length; i++) {
          let item = stock[i];
          if (currentPath === item.path && item.methods.indexOf(ctx.method) >= 0) {
            // Determine path and method
            route = item.middleware;
            break; }}if (typeof route === 'function') {
          route(ctx, next);
          return;
        }
  
        awaitnext(); }; }}module.exports = Router;
  
// Test the code app.js
const myKoa = require('./myKoa')
const app = new myKoa()

const Router = require('./router')
const router = new Router()

router.get('/index'.async ctx => { ctx.body = 'index page'; });
router.get('/post'.async ctx => { ctx.body = 'post page'; });
router.get('/list'.async ctx => { ctx.body = 'list page'; });
router.post('/index'.async ctx => { ctx.body = 'post page'; });

app.use(router.routes());
app.listen(3000)

Copy the code

Koa -static Static resource response implementation

File structure

// static.js
const fs = require("fs");
const path = require("path");

module.exports = (dirPath = "./public") = > {
  return async (ctx, next) => {
    if (ctx.url.indexOf("/public") = = =0) {
      // public starts to read files
      const url = path.resolve(__dirname, dirPath);
      const fileBaseName = path.basename(url);
      const filepath = url + ctx.url.replace("/public"."");
      console.log(filepath);
      // console.log(ctx.url,url, filepath, fileBaseName)
      try {
        stats = fs.statSync(filepath);
        if (stats.isDirectory()) {
          const dir = fs.readdirSync(filepath);
          // const
          const ret = ['<div style="padding-left:20px">'];
          dir.forEach(filename= > {
            console.log(filename);
            // Simply assume that the format without the decimal point is the folder, the actual use of statSync
            if (filename.indexOf(".") > -1) {
              ret.push(
                `<p><a style="color:black" href="${ ctx.url }/${filename}">${filename}</a></p>`
              );
            } else {
              / / file
              ret.push(
                `<p><a href="${ctx.url}/${filename}">${filename}</a></p>`); }}); ret.push("</div>");
          ctx.body = ret.join("");
        } else {
          console.log("File");

          constcontent = fs.readFileSync(filepath); ctx.body = content; }}catch (e) {
        // An error was reported that the file does not exist
        ctx.body = "404, not found"; }}else {
      // Otherwise not static resources, go directly to the next middleware
      awaitnext(); }}; };// Test the code app.js
const myKoa = require('./myKoa')
const app = new myKoa()

const static = require('./static')
app.use(static(__dirname + '/public'));

app.listen(3000)

Copy the code

Access to the address

  • Display file contents
  • http://127.0.0.1:3000/public/index.html
  • Display folder list
  • http://127.0.0.1:3000/public/