百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术文章 > 正文

使用Node.js实现一个express框架(nodejs的express框架详解)

ccwgpt 2024-11-05 09:29 25 浏览 0 评论

作者:Peter酱

转发链接:https://mp.weixin.qq.com/s/9r3_uLCx1IYdyr5BRzjQgA

express的基本用法

const express = require("express");
const app = express();

app.get("/test", (req, res, next) => {
  console.log("会所技师到位*1");
//   res.end("会所技师开始服务1");
  next();
});

app.get("/test", (req, res, next) => {
  console.log("会所技师到位*2");
  res.end("会所技师开始服务2");
});

app.listen(8888, (err) => {
  !err && console.log("会所里面有大保健吗?");
});
  • 当我访问localhost:8888/test时候,返回了:会所技师开始服务 2,服务端打印了
会所技师到位*1
会所技师到位*2
  • 从上面可以看到什么?
    • app.listen 会启动进程监听端口
    • 每次收到请求,对应的url和method会触发相应挂载在app上对应的回调函数
    • 调用 next 方法,会触发下一个
    • express默认引入调用后返回一个app对象

一起来实现一个简单的express框架

  • 定义属于我们的express文件入口,这里使用class来实现
class express {

}

module.exports = express;
  • 需要的原生模块http,创建进程监听端口
const { createServer } = require("http");
  • 给 class 定义 listen 方法,监听端口
class express {
  listen(...args) {
    createServer(cb).listen(...args);
  }
}
  • 这样就可以通过调用 class 的 listen 去调用 http 模块的listen 了,这里的cb我们可以先不管,你要知道每次接受到请求,必然会调用 cb 函数,这个是 createServer 原生模块帮我们封装好的

实现接收到请求触发

  • 实现app.get app.post等方法
    • 目前我们接受到响应,就会触发 cb 这个回调函数,那我们打印下,看看是什么参数?
class express {
  cb() {
    return (req, res) => {
      console.log(res, res, "来客人了");
    };
  }
  listen(...args) {
    createServer(this.cb()).listen(...args);
  }
}
  • 发现此时的 req 和 res 正是我们想要的可读流和可写流.
  • 开始编写 get 和 post 方法
    • 这里注意,有路由是'/'的,这种是不管任何路由都会触发一次
  constructor() {
    this.routers = {
      get: [],
      post: [],
    };
  }

  get(path, handle) {
    this.routers.get.push({
      path,
      handle,
    });
  }
  post(path, handle) {
    this.routers.post.push({
      path,
      handle,
    });
  }
  • 初始化时候定义 get、post 的数组储存对应的 path 和handle.
  • 需要触发路由回调的时候,首先要找到对应的请求方式下对应的 url的 handle 方法,然后触发回调.
  • 如何找到对应请求方式下的 url 对应的 handle 方法? 在接到请求时候就要遍历一次
    • 这里要考虑匹配多个路由,意味着,我们可能遇到像最开始一样,有两个 get 方式的 test 路由
  cb() {
    return (req, res) => {
      const method = req.method.toLowerCase();
      console.log(this.routers[method], ",method");
      const url = req.url;
      this.routers[method].forEach((item) => {
        item.path === url && item.handle(req, res);
      });
    };
  }
  listen(...args) {
    createServer(this.cb()).listen(...args);
  }
  • 上面根据 method 找到对应的数组,遍历找到请求的路由,触发回调,此时已经能正常返回数据了
[ { method: 'get', path: '/test', handle: [Function] } ] ,method
  • 此时最简单的express已经完成了,但是我们好像忘了最重要的中间件

完成最重要的中间件功能

  • 首先要知道,express中间件分两种,一种带路由的,那就是根据路由决定是否触发
  • 另外一种就是不带路由的,像静态资源这种. 是用户访问任何路由都要触发一次的
  • 那我们需要一个 all 数组储存这种任意路由都需要匹配触发的
 constructor() {
    this.routers = {
      get: [],
      post: [],
      all: [],
    };
  }
  • 之前的直接通过 push 方式是太粗暴.如果用户需要中间件功能,不传路由,那就要做特殊处理,这里通过一个中间函数处理下
  • 改造get、post方法,定义handleAddRouter方法
  handleAddRouter(path, handle) {
    let router = {};
    if (typeof path === "string") {
      router = {
        path,
        handle,
      };
    } else {
      router = {
        path: "/",
        handle: path,
      };
    }
    return router;
  }

  get(path, handle) {
    const router = this.handleAddRouter(path, handle);
    this.routers.get.push(router);
  }

  post(path, handle) {
    const router = this.handleAddRouter(path, handle);
    this.routers.post.push(router);
  }

  use(path, handle) {
    const router = this.handleAddRouter(path, handle);
    this.routers.all.push(router);
  }

  • 每次添加之前,先触发一次handleAddRouter,如果是 path 为空的中间件,直接传入函数的,那么 path 帮它设置成'/'
  • 我们还遗留了一个点,next的实现,因为我们现在加了all这个数组后,意味着可能有多个中间件,那么可能一次请求打过来,就要触发多个路由

?

这里要注意,promise.then 源码实现和 express 的 next、以及 koa 的洋葱圈、redux 的中间件实现,有着一丁点相似,当你能真的领悟前后端框架源码时候,发现大都相似

?

  • 阅读我的文章,足以击破所有前后端源码.而且可以手写出来, 我们只学最核心的,抓重点学习,野蛮生长!

实现next

  • 思路:
    • 首先要找到所有匹配的路由
    • 然后逐个执行(看 next 的调用)
  • 定义search方法,找到所有匹配的路由
  search(method, url) {
    const matchedList = [];
    [...this.routers[method], ...this.routers.all].forEach((item) => {
      item.path === url && matchedList.push(item.handle);
    });
    return matchedList;
  }

  cb() {
    return (req, res) => {
      const method = req.method.toLowerCase();
      const url = req.url;
      const matchedList = this.search(method, url);
    };
  }
  • matchedList就是我们想要找到的所有路由
  • 为了完成next,我们要将req ,res , matchedList存入闭包中,定义handle方法
  handle(req, res, matchedList) {
    const next = () => {
      const midlleware = matchedList.shift();
      if (midlleware) {
        midlleware(req, res, next);
      }
    };
    next();
  }
  cb() {
    return (req, res) => {
      const method = req.method.toLowerCase();
      const url = req.url;
      const matchedList = this.search(method, url);
      this.handle(req, res, matchedList);
    };
  }
  • 这样我们就完成了next方法,只要手动调用 next 就会调用下一个匹配到的路由回调函数
  • 不到一百行代码,就完成了这个简单的express框架

写在最后

  • 只要你根据我这些文章去认真自己实现一次,扎实学习一年拿个 P6应该没什么问题
  • 大道至简,希望你能通过这些文章真的学到框架的原理,进而自己能写出一些框架,走向更高的层级,我的所有源码仓库都在https://github.com/JinJieTan/Peter-,记得给个star

作者:Peter酱

转发链接:https://mp.weixin.qq.com/s/9r3_uLCx1IYdyr5BRzjQgA

相关推荐

用Deepseek扩写土木工程毕业论文实操指南

用Deepseek扩写毕业论文实操指南一、前期准备整理现有论文初稿/提纲列清楚论文核心框架(背景、现状、意义、方法、数据、结论等)梳理好关键文献,明确核心技术路线二、Deepseek扩写核心思路...

985学霸亲授,DeepSeek也能绘6大科研图表,5分钟就出图

在实验数据处理中,高效可视化是每个科研人的必修课。传统绘图软件操作复杂、耗时费力,而智能工具DeepSeek的出现彻底改变了这一现状。本文将详解如何用DeepSeek一键生成六大科研常用图表,从思维导...

AI写论文刷屏?大学生正在丢掉的思考力

一、宿舍深夜:当论文变成"Ctrl+C+V"凌晨两点的大学宿舍,小王对着电脑屏幕叹气。本该三天前开始写的近代史论文,此刻还一片空白。他熟练打开某AI写作网站,输入"论五四运动的...

Grok在辅助论文写作上能不能既“聪明”又“可怕”?!

AcademicIdeas-学境思源AI初稿写作随着人工智能技术的飞速发展,论文写作这一学术任务正迎来新的助力。2025年2月18日,美国xAI公司推出了备受瞩目的Grok3模型,其创始人埃隆·...

大四论文沟通场景!音频转文字难题听脑AI来化解

大四学生都知道,写论文时和导师沟通修改意见,简直是“过关斩将”。电话、语音沟通完,想把导师说的修改方向、重点要求记下来,麻烦事儿可不少。手写记不全,用普通录音转文字工具,转完还得自己慢慢找重点,稍不注...

论文写作 | 技术路线图怎么画?(提供经典优秀模板参考)

技术路线图是一种图表或文字说明,用于描述研究目标、方法和实施计划。它展示了研究的整体框架和步骤,有助于读者理解研究的逻辑和进展。在课题及论文中,技术路线图是常见的一部分,甚至是一个类似心脏一样的中枢器...

25年信息系统项目管理师考试第2批论文题目写作建议思路框架

25年信息系统项目管理师考试第2批论文题目写作建议思路框架--马军老师

微信购物应尽快纳入法律框架(微信购物管辖)

符向军近日,甘肃省工商行政管理局发布《2016年上半年信息分析报告》。报告显示,微信网购纠纷迅猛增长,网络购物投诉呈上升趋势。投诉的主要问题有出售的商品质量不过关、消费者通过微信付款后对方不发货、购买...

泛珠三角区域网络媒体与腾讯微信签署《战略合作框架协议》

新海南客户端、南海网7月14日消息(记者任桐)7月14日上午,参加第四届泛珠三角区域合作网络媒体论坛的区域网络媒体负责人及嘉宾一行到腾讯微信总部座谈交流,并签署《战略合作框架协议》(以下简称《框架协...

离线使用、植入微信-看乐心Mambo手环如何打破框架

从2014年开始智能手环就成功进入人们的生活,至今已经演变出数据监测、信息推送、心率监测等诸多五花八门的功能,人们选择智能手环并不指望其能够改变身体健康情况,更多的是通过数据来正视自身运动情况和身体健...

微信私域电商运营策略与框架(微信私域怎么做)

...

华专网络:如何零基础制作一个网站出来?

#如何零基础制作一个网站出来?#你是不是觉得网站建设很复杂,觉得自己是小白,需求不明确、流程搞不懂、怕被外包公司坑……这些问题我都懂!今天华专网络就用大白话给你捋清楚建站的全流程,让你轻松get网站制...

WAIC2024丨明日上午9点,不见不散!共同探讨智能社会与全球治理框架

大咖云集,硕果闪耀WAIC2024世界人工智能大会智能社会论坛将于7月5日9:00-12:00与你相约直播间WAIC2024上海杨浦同济大学哔哩哔哩多平台同步直播探讨智能社会与全球治理框架WAIC...

约基奇:森林狼换来戈贝尔时大家都在嘲笑 他们的阵容框架很不错

直播吧5月4日讯西部季后赛半决赛,掘金将迎战森林狼,约基奇赛前接受采访。约基奇说道:“当蒂姆-康纳利(森林狼总经理、前掘金总经理&曾选中约基奇)做了那笔交易(换来戈贝尔)时,每个人都在嘲笑他...

视频号带货为什么一个流量都没有?顶级分析框架送给你

视频号带货为什么一个流量都没有?遇到问题,一定是步步来分析内容,视频号带货一个流量都没有,用另外一个意思来讲,就可以说是零播放。为什么视频号带货一个流量都没有?跟你说再多,都不如来个分析框架。1、是否...

取消回复欢迎 发表评论: