这段代码实现了一个基于 Node.js 的 Web 框架的自动路由功能。它通过加载指定路径下的所有 controller 文件,自动创建路由映射。

代码解析:

  1. 定义 Controller 类
class Controller {
  constructor(req, res, app) {
    this.req = req
    this.res = res
    this.app = app
  }
}

exports.Controller = Controller

该代码定义了一个名为 Controller 的类,用来构建控制器对象。控制器对象包含 reqresapp 属性,分别代表请求对象、响应对象和应用程序对象。

  1. 加载控制器文件
const loadController = controllerPath => {
  const controllerMap = {}
  const files = fs.readdirSync(controllerPath)
  files.forEach(file => {
    const fileState = fs.statSync(path.join(controllerPath, file))
    if (fileState.isDirectory()) {
      controllerMap[file] = {
        isDir: true,
        ...loadController(path.join(controllerPath, file))
      }
    } else {
      const controllerName = file.substr(0, file.lastIndexOf('.'))
      if (controllerName) {
        controllerMap[controllerName] = {
          isDir: false,
          value: require(path.join(controllerPath, file))
        }
      }
    }
  })
  return controllerMap
}

loadController 函数用来加载指定路径下的所有 controller 文件,并返回一个控制器映射表。该函数通过 fs.readdirSync 获取指定路径下的所有文件,然后逐个判断文件类型:

  • 如果是目录,则递归调用 loadController 函数加载子目录下的 controller 文件;
  • 如果是文件,则读取文件内容,并将控制器名称和控制器对象存储在 controllerMap 中。
  1. 创建代理对象
const errMsg = message => ({ code: 1, message, data: null })
const createProxy = (controllerMap, app) => {
  return new Proxy(controllerMap, {
    get(target, name) {
      if (target[name]) {
        if (!target[name].isDir) {
          return new Proxy(target[name], {
            get(target, name) {
              return (req, res) => {
                if (Object.getOwnPropertyNames(target.value.prototype).includes(name)) {
                  new target.value(req, res, app)[name]()
                } else {
                  res.send(errMsg('method not exist'))
                }
              }
            }
          })
        } else {
          return createProxy(target[name], app)
        }
      } else {
        return new Proxy({}, {
          get() {
            return (req, res) => {
              res.send(errMsg('controller not exist'))
            }
          }
        })
      }
    }
  })
}

createProxy 函数创建一个代理对象,用来实现控制器的自动路由功能。代理对象会在访问控制器时自动创建路由,并根据请求方法调用对应的控制器方法。

该函数使用 Proxy 对象来代理 controllerMap。当访问 controllerMap 中的某个属性时,get 方法会被调用。该方法根据属性类型进行不同的处理:

  • 如果是控制器对象,则创建一个新的代理对象,该代理对象会根据请求方法调用对应的控制器方法;
  • 如果是子目录,则递归调用 createProxy 函数创建子目录的代理对象;
  • 如果不存在,则返回一个默认的代理对象,返回错误信息。
  1. 导出模块
const controllerMap = loadController(path.join(__dirname, '../controller'))

module.exports = app => {
  app.controller = createProxy(controllerMap, app)
  return (req, res, next) => {
    next()
  }
}

该代码段将 createProxy 函数应用于加载的控制器映射表,并将其赋值给 app 对象的 controller 属性,用于后续路由的访问。同时,返回一个中间件函数,用于在请求处理管道中添加路由功能。

代码优化建议:

  1. 使用异步方式读取文件,避免阻塞主线程。
  2. 优化代码逻辑,减少冗余代码,提高可读性。
  3. 使用缓存机制,提高路由匹配效率。
  4. 增加错误处理机制,避免程序异常退出。

总结:

这段代码通过 Proxy 对象和递归方式实现了 Web 框架的自动路由功能,能够根据 controller 文件自动创建路由映射,简化了路由配置过程。

相关知识点:

  • Node.js 核心模块 fspath
  • Proxy 对象
  • 中间件
  • 路由映射
  • 递归
  • 异步编程
  • 错误处理
Node.js Web 框架自动路由实现 - 代码解析

原文地址: https://www.cveoy.top/t/topic/nhze 著作权归作者所有。请勿转载和采集!

免费AI点我,无需注册和登录