使用Node.js实现一个express框架(nodejs的express框架详解)
ccwgpt 2024-11-05 09:29 29 浏览 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
相关推荐
- 一个基于.Net Core遵循Clean Architecture原则开源架构
-
今天给大家推荐一个遵循CleanArchitecture原则开源架构。项目简介这是基于Asp.netCore6开发的,遵循CleanArchitecture原则,可以高效、快速地构建基于Ra...
- AI写代码翻车无数次,我发现只要提前做好这3步,bug立减80%
-
写十万行全是bug之后终于找到方法了开发"提示词管理助手"新版本那会儿,我差点被bug整崩溃。刚开始两周,全靠AI改代码架构,结果十万行程序漏洞百出。本来以为AI说没问题就稳了,结果...
- OneCode低代码平台的事件驱动设计:架构解析与实践
-
引言:低代码平台的事件驱动范式在现代软件开发中,事件驱动架构(EDA)已成为构建灵活、松耦合系统的核心范式。OneCode低代码平台通过创新性的注解驱动设计,将事件驱动理念深度融入平台架构,实现了业务...
- 国内大厂AI插件评测:根据UI图生成Vue前端代码
-
在IDEA中安装大厂的AI插件,打开ruoyi增强项目:yudao-ui-admin-vue31.CodeBuddy插件登录腾讯的CodeBuddy后,大模型选择deepseek-v3,输入提示语:...
- AI+低代码技术揭秘(二):核心架构
-
本文档介绍了为VTJ低代码平台提供支持的基本架构组件,包括Engine编排层、Provider服务系统、数据模型和代码生成管道。有关UI组件库和widget系统的信息,请参阅UI...
- GitDiagram用AI把代码库变成可视化架构图
-
这是一个名为gitdiagram的开源工具,可将GitHub仓库实时转换为交互式架构图,帮助开发者快速理解代码结构。核心功能一键可视化:替换GitHubURL中的"hub...
- 30天自制操作系统:第六天:代码架构整理与中断处理
-
1.拆开bootpack.c文件。根据设计模式将对应的功能封装成独立的文件。2.初始化pic:pic(可编程中断控制器):在设计上,cpu单独只能处理一个中断。而pic是将8个中断信号集合成一个中断...
- AI写代码越帮越忙?2025年研究揭露惊人真相
-
近年来,AI工具如雨后春笋般涌现,许多人开始幻想程序员的未来就是“对着AI说几句话”,就能轻松写出完美的代码。然而,2025年的一项最新研究却颠覆了这一期待,揭示了一个令人意外的结果。研究邀请了16位...
- 一键理解开源项目:两个自动生成GitHub代码架构图与说明书工具
-
一、GitDiagram可以一键生成github代码仓库的架构图如果想要可视化github开源项目:https://github.com/luler/reflex_ai_fast,也可以直接把域名替换...
- 5分钟掌握 c# 网络通讯架构及代码示例
-
以下是C#网络通讯架构的核心要点及代码示例,按协议类型分类整理:一、TCP协议(可靠连接)1.同步通信//服务器端usingSystem.Net.Sockets;usingTcpListene...
- 从复杂到优雅:用建造者和责任链重塑代码架构
-
引用设计模式是软件开发中的重要工具,它为解决常见问题提供了标准化的解决方案,提高了代码的可维护性和可扩展性,提升了开发效率,促进了团队协作,提高了软件质量,并帮助开发者更好地适应需求变化。通过学习和应...
- 低代码开发当道,我还需要学习LangChain这些框架吗?| IT杂谈
-
专注LLM深度应用,关注我不迷路前两天有位兄弟问了个问题:当然我很能理解这位朋友的担忧:期望效率最大化,时间用在刀刃上,“不要重新发明轮子”嘛。铺天盖地的AI信息轰炸与概念炒作,很容易让人浮躁与迷茫。...
- 框架设计并不是简单粗暴地写代码,而是要先弄清逻辑
-
3.框架设计3.框架设计本节我们要开发一个UI框架,底层以白鹭引擎为例。框架设计的第一步并不是直接撸代码,而是先想清楚设计思想,抽象。一个一个的UI窗口是独立的吗?不是的,...
- 大佬用 Avalonia 框架开发的 C# 代码 IDE
-
AvalonStudioAvalonStudio是一个开源的跨平台的开发编辑器(IDE),AvalonStudio的目标是成为一个功能齐全,并且可以让开发者快速使用的IDE,提高开发的生产力。A...
- 轻量级框架Lagent 仅需20行代码即可构建自己的智能代理
-
站长之家(ChinaZ.com)8月30日消息:Lagent是一个专注于基于LLM模型的代理开发的轻量级框架。它的设计旨在简化和提高这种模型下代理的开发效率。LLM模型是一种强大的工具,可以...
你 发表评论:
欢迎- 一周热门
- 最近发表
- 标签列表
-
- 框架图 (58)
- flask框架 (53)
- quartz框架 (51)
- abp框架 (47)
- springmvc框架 (49)
- 分布式事务框架 (65)
- scrapy框架 (56)
- shiro框架 (61)
- 定时任务框架 (56)
- java日志框架 (61)
- mfc框架 (52)
- abb框架断路器 (48)
- beego框架 (52)
- java框架spring (58)
- grpc框架 (65)
- tornado框架 (48)
- 前端框架bootstrap (54)
- orm框架有哪些 (51)
- 知识框架图 (52)
- ppt框架 (55)
- 框架图模板 (59)
- 内联框架 (52)
- cad怎么画框架 (58)
- ssm框架实现登录注册 (49)
- oracle字符串长度 (48)