JavaScript 实现类似Express的中间件系统(实例详解)

来详细讲解一下“JavaScript 实现类似Express的中间件系统(实例详解)”的攻略。

简介

中间件是实现 Express 等框架功能的核心。本文主要讲解如何通过 JavaScript 实现一个类似 Express 的中间件系统。

实现过程

1. 实现基本的 Application

首先,我们需要创建一个 Application 类,表示整个应用。这个类需要实现以下功能:

  • 注册路由和中间件
  • 解析请求体和响应头
  • 处理错误
class Application {
  constructor() {
    // 路由和中间件列表
    this.routes = {
      all: [],
      get: [],
      post: []
    };
  }

  // 注册路由和中间件
  use(path, middleware) {
    let info = {};
    if (typeof path === "string") {
      info.path = path;
      info.middleware = middleware;
    } else {
      info.path = "/";
      info.middleware = path;
    }
    this.routes.all.push(info);
  }

  // 处理请求
  handle(req, res) {
    let self = this;
    let idx = 0;
    let stack = self.routes.all;

    function next() {
      let middleware = stack[idx];
      if (!middleware) return;
      if (middleware.path === "/" || middleware.path === req.path || middleware.path === req.url) {
        middleware.middleware(req, res, next);
      } else {
        next();
      }
    }

    next();
  }

  // 监听端口
  listen(...args) {
    let server = http.createServer(this.handle.bind(this));
    server.listen(...args);
  }
}

2. 实现中间件

中间件的实现方式很简单,它们是一个函数,接收 reqresnext 三个参数,最后必须调用 next,否则后续的中间件将无法执行。

3. 注册路由和中间件

我们可以通过 use 方法注册路由和中间件,这个方法接收两个参数,第一个参数表示路径,可以是字符串或正则表达式;第二个参数表示中间件。

4. 处理请求

在处理请求时,我们需要遍历所有注册的中间件和路由,直到找到匹配的路由或中间件,然后依次执行它们。

class Application {
  // 省略其他代码

  handle(req, res) {
    let self = this;
    let idx = 0;
    // 获取指定方法类型的路由和中间件
    let method = req.method.toLowerCase();
    let stack = self.routes.all.concat(self.routes[method]);

    function next() {
      let middleware = stack[idx];
      if (!middleware) return;
      // 匹配路径
      if (middleware.path === "/" || middleware.path === req.path || middleware.path === req.url) {
        middleware.middleware(req, res, next);
      } else {
        idx++;
        next();
      }
    }

    next();
  }
}

5. 解析请求体和响应头

为了方便使用,在解析请求体和响应头时,我们可以定义一些常见的中间件,如下:

// 解析 JSON 格式请求体
const bodyParserJSON = function (req, res, next) {
  let data = "";
  req.on("data", function (chunk) {
    data += chunk;
  });
  req.on("end", function () {
    try {
      req.body = JSON.parse(data);
      next();
    } catch (err) {
      res.statusCode = 400;
      return res.end("bad request.");
    }
  });
};

// 解析表单请求体
const bodyParserUrlencoded = function (req, res, next) {
  let data = "";
  req.on("data", function (chunk) {
    data += chunk;
  });
  req.on("end", function () {
    req.body = qs.parse(data);
    next();
  });
};

// 设置响应头
const setContentType = function (req, res, next) {
  res.setHeader("Content-Type", "text/html;charset=utf-8");
  next();
};

6. 错误处理

最后,在处理请求过程中,难免会出现一些错误。我们可以通过全局中间件来捕获错误并处理,如下:

// 全局错误处理中间件
const errorHandler = function (err, req, res, next) {
  console.error(err);
  res.statusCode = 500;
  res.end("Internal Server Error");
};

app.use(setContentType);
app.use(bodyParserJSON);
app.use(bodyParserUrlencoded);
app.use(errorHandler);

示例说明

接下来,我们使用上述代码创建一个简单的 HTTP 服务器,并实现以下两个接口:

  • GET /,返回 “Hello World!”
  • POST /api/user,返回请求体中的 name 字段
const http = require("http");
const { parse } = require("url");
const qs = require("qs");

class Application {
  constructor() {
    // 路由和中间件列表
    this.routes = {
      all: [],
      get: [],
      post: []
    };
  }

  // 注册路由和中间件
  use(path, middleware) {
    let info = {};
    if (typeof path === "string") {
      info.path = path;
      info.middleware = middleware;
    } else {
      info.path = "/";
      info.middleware = path;
    }
    this.routes.all.push(info);
  }

  // 处理请求
  handle(req, res) {
    let self = this;
    let idx = 0;
    // 获取指定方法类型的路由和中间件
    let method = req.method.toLowerCase();
    let stack = self.routes.all.concat(self.routes[method]);

    function next() {
      let middleware = stack[idx];
      if (!middleware) return;
      // 匹配路径
      if (middleware.path === "/" || middleware.path === req.path || middleware.path === req.url) {
        middleware.middleware(req, res, next);
      } else {
        idx++;
        next();
      }
    }

    next();
  }

  // 监听端口
  listen(...args) {
    let server = http.createServer(this.handle.bind(this));
    server.listen(...args);
  }
}

// 解析 JSON 格式请求体
const bodyParserJSON = function (req, res, next) {
  let data = "";
  req.on("data", function (chunk) {
    data += chunk;
  });
  req.on("end", function () {
    try {
      req.body = JSON.parse(data);
      next();
    } catch (err) {
      res.statusCode = 400;
      return res.end("bad request.");
    }
  });
};

// 解析表单请求体
const bodyParserUrlencoded = function (req, res, next) {
  let data = "";
  req.on("data", function (chunk) {
    data += chunk;
  });
  req.on("end", function () {
    req.body = qs.parse(data);
    next();
  });
};

// 设置响应头
const setContentType = function (req, res, next) {
  res.setHeader("Content-Type", "text/html;charset=utf-8");
  next();
};

// 全局错误处理中间件
const errorHandler = function (err, req, res, next) {
  console.error(err);
  res.statusCode = 500;
  res.end("Internal Server Error");
};

let app = new Application();

// GET /
app.use("/", function (req, res) {
  res.end("Hello World!");
});

// POST /api/user
app.use("/api/user", bodyParserJSON, function (req, res) {
  res.end(`Hello ${req.body.name}!`);
});

app.use(setContentType);
app.use(bodyParserUrlencoded);
app.use(errorHandler);

app.listen(3000, function () {
  console.log("Server started, listening on port 3000.");
});

运行上述代码后,在浏览器中访问 http://localhost:3000 将会返回 Hello World!,在 Postman 等工具中发送 POST 请求,请求体包含一个 name 字段,则会返回 Hello xxx!

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:JavaScript 实现类似Express的中间件系统(实例详解) - Python技术站

(0)
上一篇 2023年5月28日
下一篇 2023年5月28日

相关文章

  • 在网页里看flash的trace数据的js类

    要在网页中查看Flash的trace数据,可以使用以下步骤: 导出trace数据在Flash中,使用trace()函数输出调试信息。在发布Flash时,选择“在文件中编写日志文件”选项。这样,在运行Flash时,会在指定的位置生成一个日志文件。 导入trace数据到网页中导入trace数据的工具是js类,例如:FlashConsole。FlashConsol…

    JavaScript 2023年6月10日
    00
  • 把json格式的字符串转换成javascript对象或数组的方法总结

    让我来讲解一下“把json格式的字符串转换成javascript对象或数组的方法总结”。 什么是JSON JSON(JavaScript Object Notation)是一种轻量级的数据交换格式。它由Douglas Crockford在2001年创造。JSON 采用完全独立于语言的文本格式,具有简洁明了、易于读写的特点,是广泛应用于Web应用程序之中的文本…

    JavaScript 2023年5月27日
    00
  • 20行js代码实现的贪吃蛇小游戏

    20行js代码实现的贪吃蛇小游戏攻略 1. 实现思路 该贪吃蛇小游戏的实现思路非常简单,主要分为以下两步: 初始化游戏BOSS。 在游戏中添加监听事件,监听玩家的操作,并处理游戏逻辑。 2. 代码实现 游戏的实现代码如下: with(document){ a = appendChild(createElement("canvas")).g…

    JavaScript 2023年5月27日
    00
  • javascript读取本地文件和目录方法详解

    JavaScript读取本地文件和目录方法详解 概述 JavaScript是一种可以在页面上运行的脚本语言,其主要作用是改变页面上元素的行为和外观,实现更加友好和丰富的用户交互。在某些场景下,我们需要读取本地文件或目录内容,此时需要借助一些JS库或API来实现。 读取本地文件 使用File API 在HTML5中,有一个File API,该API提供了读取用…

    JavaScript 2023年5月27日
    00
  • Javascript toString 方法

    以下是关于JavaScript toString方法的完整攻略。 JavaScript toString方法 JavaScript toString方法是Number对象的一个方法,用于将数字转换为字符串。我们可以使用toString方法来将数字转换为不同进制的字符串,如二进制、八进制、十六进制。 下面是一个使用toString方法的示例: var num …

    JavaScript 2023年5月11日
    00
  • JS设置cookie、读取cookie、删除cookie

    下面是JS设置cookie、读取cookie、删除cookie的完整攻略: 1. 设置Cookie 我们可以通过JS来设置cookie,具体方法如下: // 设置cookie document.cookie = "cookieName=cookieVal; expires=Sun, 1 Jan 2023 00:00:00 UTC; path=/&q…

    JavaScript 2023年6月11日
    00
  • JavaScript判断DOM何时加载完毕的技巧

    JavaScript是一门运行在客户端的编程语言,它可以操作和控制网页中的元素和内容。但有些时候,我们需要确保DOM加载完毕后再执行JavaScript代码,因为如果在DOM加载之前执行JavaScript代码,可能会出现错误。 以下是判断DOM何时加载完毕的几种技巧: 1. window.onload window.onload是最常用的判断DOM是否加载…

    JavaScript 2023年6月10日
    00
  • JavaScript实现cookie的操作

    下面是详细讲解 JavaScript 实现 Cookie 操作的攻略。 什么是 Cookie Cookie(中文翻译为“网页 Cookie”或者“浏览器 Cookie”)是网站为了辨别用户身份的一种标识,是存在用户本地终端上的数据。Cookie 是小型文本文件,由网站服务器发送给用户浏览器,浏览器会将其存储在本地,之后每次请求该网站时都会携带该 Cookie…

    JavaScript 2023年6月11日
    00
合作推广
合作推广
分享本页
返回顶部