Express 是 Node.js 中极其常用的 Web 服务器应用程序框架。本质上,框架是一种遵循特定规则的代码结构,具有两个关键特征:
- 封装了API,让开发者能够更加专注于业务代码的编写。
- 已建立流程和标准规范。
Express框架的核心特性如下:
- 它可以配置中间件来响应各种HTTP请求。
- 它定义了一个路由表,用于执行不同类型的HTTP请求操作。
- 支持向模板传递参数,实现HTML页面的动态渲染。
本文将通过实现一个简单的 LikeExpress 类来分析 Express 如何实现中间件注册、下一个机制以及路由处理。
快速分析
我们首先通过两个 Express 代码示例来探索它提供的功能:
Express 官网 Hello World 示例
const express = require('express'); const app = express(); const port = 3000; app.get('/', (req, res) => { res.send('Hello World!'); }); app.listen(port, () => { console.log(`Example app listening at http://localhost:${port}`); });
入口文件app.js分析
以下是express-generator脚手架生成的Express项目的入口文件app.js的代码:
// Handle errors caused by unmatched routes const createError = require('http-errors'); const express = require('express'); const path = require('path'); const indexRouter = require('./routes/index'); const usersRouter = require('./routes/users'); // `app` is an Express instance const app = express(); // View engine setup app.set('views', path.join(__dirname, 'views')); app.set('view engine', 'jade'); // Parse JSON format data in post requests and add the `body` field to the `req` object app.use(express.json()); // Parse the urlencoded format data in post requests and add the `body` field to the `req` object app.use(express.urlencoded({ extended: false })); // Static file handling app.use(express.static(path.join(__dirname, 'public'))); // Register top-level routes app.use('/', indexRouter); app.use('/users', usersRouter); // Catch 404 errors and forward them to the error handler app.use((req, res, next) => { next(createError(404)); }); // Error handling app.use((err, req, res, next) => { // Set local variables to display error messages in the development environment res.locals.message = err.message; // Decide whether to display the full error according to the environment variable. Display in development, hide in production. res.locals.error = req.app.get('env') === 'development'? err : {}; // Render the error page res.status(err.status || 500); res.render('error'); }); module.exports = app;
从上面两段代码可以看出,Express实例应用程序主要有三个核心方法:
-
app.use([path,]callback[,callback...]):用于注册中间件。当请求路径符合设定的规则时,就会执行相应的中间件函数。
- path:指定调用中间件函数的路径。
- 回调:回调函数可以采用多种形式。它可以是单个中间件函数、一系列用逗号分隔的中间件函数、中间件函数数组或以上所有函数的组合。
- app.get() 和 app.post():这些方法与 use() 类似,也是用于注册中间件。但是,它们绑定到 HTTP 请求方法。只有使用对应的HTTP请求方法才会触发相关中间件的注册。
- app.listen():负责创建一个httpServer并传递server.listen()所需的参数。
代码实现
通过对Express代码功能的分析,我们知道Express的实现重点关注三点:
- 中间件函数的注册过程。
- 中间件功能中的核心next机制。
- 路由处理,重点是路径匹配。
基于这些点,我们将在下面实现一个简单的 LikeExpress 类。
1. 类的基本结构
首先明确该类需要实现的主要方法:
- use():实现通用中间件注册。
- get() 和 post():实现HTTP请求相关的中间件注册。
- Listen():本质上就是httpServer的listen()函数。在该类的listen()函数中,创建了一个httpServer,传入参数,监听请求,回调函数(req, res) => {} 已执行。
回顾原生Node httpServer的使用:
const express = require('express'); const app = express(); const port = 3000; app.get('/', (req, res) => { res.send('Hello World!'); }); app.listen(port, () => { console.log(`Example app listening at http://localhost:${port}`); });
相应地,LikeExpress类的基本结构如下:
// Handle errors caused by unmatched routes const createError = require('http-errors'); const express = require('express'); const path = require('path'); const indexRouter = require('./routes/index'); const usersRouter = require('./routes/users'); // `app` is an Express instance const app = express(); // View engine setup app.set('views', path.join(__dirname, 'views')); app.set('view engine', 'jade'); // Parse JSON format data in post requests and add the `body` field to the `req` object app.use(express.json()); // Parse the urlencoded format data in post requests and add the `body` field to the `req` object app.use(express.urlencoded({ extended: false })); // Static file handling app.use(express.static(path.join(__dirname, 'public'))); // Register top-level routes app.use('/', indexRouter); app.use('/users', usersRouter); // Catch 404 errors and forward them to the error handler app.use((req, res, next) => { next(createError(404)); }); // Error handling app.use((err, req, res, next) => { // Set local variables to display error messages in the development environment res.locals.message = err.message; // Decide whether to display the full error according to the environment variable. Display in development, hide in production. res.locals.error = req.app.get('env') === 'development'? err : {}; // Render the error page res.status(err.status || 500); res.render('error'); }); module.exports = app;
2. 中间件注册
从 app.use([path,]callback[,callback...]) 中,我们可以看到中间件可以是函数数组,也可以是单个函数。为了简化实现,我们将中间件统一处理为函数数组。 LikeExpress类中use()、get()、post()这三个方法都可以实现中间件注册。只是由于请求方式不同,触发的中间件有所不同。所以我们考虑:
- 抽象出一个通用的中间件注册函数。
- 为这三个方法创建中间件函数数组,用于存储不同请求对应的中间件。由于use()是所有请求的通用中间件注册方法,因此存储use()中间件的数组是get()和post()数组的并集。
中间件队列数组
中间件数组需要放置在公共区域,以便于类中的方法访问。所以,我们把中间件数组放在constructor()构造函数中。
const http = require("http"); const server = http.createServer((req, res) => { res.end("hello"); }); server.listen(3003, "127.0.0.1", () => { console.log("node service started successfully"); });
中间件注册功能
中间件注册是指将中间件存储在对应的中间件数组中。中间件注册函数需要解析传入的参数。第一个参数可能是路由,也可能是中间件,所以需要先判断是否是路由。如果是,则原样输出;否则默认为根路由,然后将剩余的中间件参数转为数组。
const http = require('http'); class LikeExpress { constructor() {} use() {} get() {} post() {} // httpServer callback function callback() { return (req, res) => { res.json = function (data) { res.setHeader('content-type', 'application/json'); res.end(JSON.stringify(data)); }; }; } listen(...args) { const server = http.createServer(this.callback()); server.listen(...args); } } module.exports = () => { return new LikeExpress(); };
use()、get() 和 post() 的实现
通过通用的中间件注册函数register(),很容易实现use()、get()、post(),只需将中间件存储在对应的数组中即可。
const express = require('express'); const app = express(); const port = 3000; app.get('/', (req, res) => { res.send('Hello World!'); }); app.listen(port, () => { console.log(`Example app listening at http://localhost:${port}`); });
3. 路由匹配处理
当注册函数的第一个参数是路由时,只有当请求路径匹配该路由或者是其子路由时,才会触发相应的中间件函数。所以,我们需要一个路由匹配函数,根据请求方法和请求路径提取匹配路由的中间件数组,供后续的callback()函数执行:
// Handle errors caused by unmatched routes const createError = require('http-errors'); const express = require('express'); const path = require('path'); const indexRouter = require('./routes/index'); const usersRouter = require('./routes/users'); // `app` is an Express instance const app = express(); // View engine setup app.set('views', path.join(__dirname, 'views')); app.set('view engine', 'jade'); // Parse JSON format data in post requests and add the `body` field to the `req` object app.use(express.json()); // Parse the urlencoded format data in post requests and add the `body` field to the `req` object app.use(express.urlencoded({ extended: false })); // Static file handling app.use(express.static(path.join(__dirname, 'public'))); // Register top-level routes app.use('/', indexRouter); app.use('/users', usersRouter); // Catch 404 errors and forward them to the error handler app.use((req, res, next) => { next(createError(404)); }); // Error handling app.use((err, req, res, next) => { // Set local variables to display error messages in the development environment res.locals.message = err.message; // Decide whether to display the full error according to the environment variable. Display in development, hide in production. res.locals.error = req.app.get('env') === 'development'? err : {}; // Render the error page res.status(err.status || 500); res.render('error'); }); module.exports = app;
然后,在httpServer的回调函数callback()中,提取出需要执行的中间件:
const http = require("http"); const server = http.createServer((req, res) => { res.end("hello"); }); server.listen(3003, "127.0.0.1", () => { console.log("node service started successfully"); });
四、下一个机制的实施
Express中间件函数的参数为req、res、next,其中next是一个函数。只有调用它,中间件函数才能按顺序执行,类似于ES6 Generator中的next()。在我们的实现中,我们需要编写一个具有以下要求的 next() 函数:
- 每次从中间件队列数组中按顺序提取一个中间件。
- 将 next() 函数传递到提取的中间件中。由于中间件数组是公共的,因此每次执行next()时,都会取出数组中的第一个中间件函数执行,从而达到中间件顺序执行的效果。
const http = require('http'); class LikeExpress { constructor() {} use() {} get() {} post() {} // httpServer callback function callback() { return (req, res) => { res.json = function (data) { res.setHeader('content-type', 'application/json'); res.end(JSON.stringify(data)); }; }; } listen(...args) { const server = http.createServer(this.callback()); server.listen(...args); } } module.exports = () => { return new LikeExpress(); };
快捷代码
constructor() { // List of stored middleware this.routes = { all: [], // General middleware get: [], // Middleware for get requests post: [], // Middleware for post requests }; }
Leapcell:用于 Web 托管、异步任务和 Redis 的下一代无服务器平台
最后给大家介绍一个非常适合部署Express的平台:Leapcell。
Leapcell 是一个无服务器平台,具有以下特征:
1. 多语言支持
- 使用 JavaScript、Python、Go 或 Rust 进行开发。
2.免费部署无限个项目
- 只需支付使用费用——无请求,不收费。
3. 无与伦比的成本效益
- 即用即付,无闲置费用。
- 示例:25 美元支持 694 万个请求,平均响应时间为 60 毫秒。
4.简化的开发者体验
- 直观的用户界面,轻松设置。
- 完全自动化的 CI/CD 管道和 GitOps 集成。
- 实时指标和日志记录以获取可行的见解。
5. 轻松的可扩展性和高性能
- 自动扩展以轻松处理高并发。
- 零运营开销——只需专注于构建。
在文档中探索更多内容!
Leapcell Twitter:https://x.com/LeapcellHQ
以上是掌握 Express.js:深入探讨的详细内容。更多信息请关注PHP中文网其他相关文章!

JavaScript框架的强大之处在于简化开发、提升用户体验和应用性能。选择框架时应考虑:1.项目规模和复杂度,2.团队经验,3.生态系统和社区支持。

引言我知道你可能会觉得奇怪,JavaScript、C 和浏览器之间到底有什么关系?它们之间看似毫无关联,但实际上,它们在现代网络开发中扮演着非常重要的角色。今天我们就来深入探讨一下这三者之间的紧密联系。通过这篇文章,你将了解到JavaScript如何在浏览器中运行,C 在浏览器引擎中的作用,以及它们如何共同推动网页的渲染和交互。JavaScript与浏览器的关系我们都知道,JavaScript是前端开发的核心语言,它直接在浏览器中运行,让网页变得生动有趣。你是否曾经想过,为什么JavaScr

Node.js擅长于高效I/O,这在很大程度上要归功于流。 流媒体汇总处理数据,避免内存过载 - 大型文件,网络任务和实时应用程序的理想。将流与打字稿的类型安全结合起来创建POWE

Python和JavaScript在性能和效率方面的差异主要体现在:1)Python作为解释型语言,运行速度较慢,但开发效率高,适合快速原型开发;2)JavaScript在浏览器中受限于单线程,但在Node.js中可利用多线程和异步I/O提升性能,两者在实际项目中各有优势。

JavaScript起源于1995年,由布兰登·艾克创造,实现语言为C语言。1.C语言为JavaScript提供了高性能和系统级编程能力。2.JavaScript的内存管理和性能优化依赖于C语言。3.C语言的跨平台特性帮助JavaScript在不同操作系统上高效运行。

JavaScript在浏览器和Node.js环境中运行,依赖JavaScript引擎解析和执行代码。1)解析阶段生成抽象语法树(AST);2)编译阶段将AST转换为字节码或机器码;3)执行阶段执行编译后的代码。

Python和JavaScript的未来趋势包括:1.Python将巩固在科学计算和AI领域的地位,2.JavaScript将推动Web技术发展,3.跨平台开发将成为热门,4.性能优化将是重点。两者都将继续在各自领域扩展应用场景,并在性能上有更多突破。

Python和JavaScript在开发环境上的选择都很重要。1)Python的开发环境包括PyCharm、JupyterNotebook和Anaconda,适合数据科学和快速原型开发。2)JavaScript的开发环境包括Node.js、VSCode和Webpack,适用于前端和后端开发。根据项目需求选择合适的工具可以提高开发效率和项目成功率。


热AI工具

Undresser.AI Undress
人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover
用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool
免费脱衣服图片

Clothoff.io
AI脱衣机

Video Face Swap
使用我们完全免费的人工智能换脸工具轻松在任何视频中换脸!

热门文章

热工具

Dreamweaver Mac版
视觉化网页开发工具

WebStorm Mac版
好用的JavaScript开发工具

MinGW - 适用于 Windows 的极简 GNU
这个项目正在迁移到osdn.net/projects/mingw的过程中,你可以继续在那里关注我们。MinGW:GNU编译器集合(GCC)的本地Windows移植版本,可自由分发的导入库和用于构建本地Windows应用程序的头文件;包括对MSVC运行时的扩展,以支持C99功能。MinGW的所有软件都可以在64位Windows平台上运行。

EditPlus 中文破解版
体积小,语法高亮,不支持代码提示功能

适用于 Eclipse 的 SAP NetWeaver 服务器适配器
将Eclipse与SAP NetWeaver应用服务器集成。