目录
引言
在前面的学习中,我们成功搭建了Express框架,并领略了其轻量级和易于上手的特点,这为我们的Web应用开发奠定了坚实的基础。然而,Express框架的精髓远不止于此。其真正强大的地方在于它拥有一个丰富且成熟的生态系统,这个生态系统中最引人注目的便是中间件(Middleware)机制。
中间件作为Express框架的灵魂,不仅扩展了框架的功能,还提高了应用的灵活性和可维护性。通过中间件,我们可以轻松地对请求和响应进行预处理和后处理,实现诸如日志记录、身份验证、错误处理等功能。更重要的是,Express的中间件机制允许我们编写可复用的代码片段,这些代码片段可以在多个应用中共享,大大提高了开发效率。
在本文中,我们将使用Express的中间件,了解如何使用它们来构建更加健壮和高效的Web应用。希望通过本文的学习,读者能够深刻体会到Express框架中间件的强大之处,并在自己的项目中灵活运用它们。
一、开发环境必备:数据库
1.1 本地环境创建数据库
本篇使用的是MySQL
,而其他数据库,基本大差不差。
-- 创建数据库
CREATE DATABASE IF NOT EXISTS db_min
-- 创建用户表
CREATE TABLE IF NOT EXISTS user (
id INT PRIMARY KEY AUTO_INCREMENT,
username VARCHAR(50) NOT NULL,
password VARCHAR(50) NOT NULL
)
-- 插入六条数据
INSERT INTO user (username, password) VALUES
('张三', '123456'),
('李四', '123456'),
('王五', '123456'),
('赵六', '123456'),
('老王', '123456'),
('小三', '123456')
1.2 连接数据库
在Node.js的Express框架中,连接MySQL数据库可以通过两种主要方式实现:
- 使用
mysql2
原生客户端:mysql2
是MySQL的官方Node.js客户端,它允许你直接与MySQL数据库进行交互。这种方式比较直接和底层,你可以精确控制数据库操作,执行SQL查询,获取结果。但这也意味着你需要自己处理所有的SQL语句,并且要特别注意防止SQL注入等安全问题。 - 使用
mysql2
+knex
组合:knex
是一个SQL查询构建器,它提供了一个更高级的抽象层,让你可以用JavaScript代码来构建SQL查询,而不是直接编写SQL语句。knex
与mysql2
结合使用,可以让你以一种更简洁、更安全的方式操作数据库。knex
支持多种数据库,包括MySQL,并且提供了诸如事务管理、迁移、连接池等高级功能。
简单来说,如果你喜欢直接控制数据库操作,不介意手动编写SQL语句,可以选择使用mysql2
。如果你希望以一种更现代、更安全的方式来管理数据库操作,并且想要利用一些高级功能,那么mysql2
结合knex
可能是更好的选择。
1.2.1 使用mysql2
原生客户端
① 安装 mysql2
npm install mysql2
② 编写数据库配置文件
//src/common/config/index.js
module.exports = {
MySQLConfig: {
host: "localhost",
user: "root",
password: "123456",
database: "db_min",
// 是否等待所有连接都被处理。如果设置为true,则当连接池达到其最大容量时,新请求将被阻塞,直到有可用连接
waitForConnections: true,
connectionLimit: 10, // 允许的最大连接数。如果超过这个数量,新的连接将被拒绝
// 队列限制。如果设置为0,则没有限制,更多的请求将被添加到队列中,直到达到最大连接数
queueLimit: 0,
},
};
③ 连接数据库
//src/common/utils/db.js
const mysql = require("mysql2");
const { MySQLConfig } = require("../config");
// 创建连接池
const pool = mysql.createPool(MySQLConfig);
module.exports = pool.promise();
④ 使用数据库
// UserDao.js
const db = require("../common/utils/db");
class UserDao {
async getUserList() {
let sql = "select * from user";
const data = await db.execute(sql);
// 使用 data[0] 的原因,请查阅 mysql2 文档。本文重点在快速实践,深入理论需自行学习。
// 如果你深入理论学会后,还望慷慨分享,让我们共同成长和学习。
return data[0];
}
}
module.exports = new UserDao();
1.2.2 使用mysql2
+ knex
组合
① 安装 mysql2
和 knex
npm install knex mysql2
② 初始化 knex
//src/common/config/index.js
module.exports = {
MySQLConfig: {
client: "mysql2",
connection: {
host: "localhost",
user: "root",
password: "123456",
database: "db_min",
},
pool: {
// 连接池配置
min: 0,
max: 10,
},
},
};
③ 创建和使用 knex
实例
//src/common/utils/db.js
const { MySQLConfig } = require("../config");
const knex = require("knex")(MySQLConfig);
// 监听 'query' 事件
knex.on("query", (query) => {
console.log("SQL Statement:", query.sql);
});
// 监听 'query-response' 事件,获取查询结果
knex.on("query-response", (response, query) => {
console.log("SQL Query Result Count:", response.length);
});
module.exports = knex;
//UserDao.js
const db = require("../common/utils/db");
class UserDao {
async getUserList() {
return await db.select('*').from('user');
}
}
module.exports = new UserDao();
1.2.3 校验接口
1.2.4 总结
两种方式都允许你将Express.js应用连接到MySQL数据库,但使用knex
提供了一个更高级的抽象,使得查询构建、事务处理和数据库迁移等操作更为简单和安全。而直接使用mysql2
则提供了更直接的控制,可能更适合那些需要精细调整数据库操作的场景。
萝卜青菜各有所爱,具体还是看业务需求。笔者个人更倾向于mysql2
和knex
的组合使用,既享受了knex
带来的便利,又不失对数据库操作的精细控制。
二、接收POST请求
因为Express
开发初期,目的在于轻量级,从而舍弃了部分功能,而解析POST请求便被舍弃了,故而在4.x
以前,一般使用body-parser
来解析。
但在 Express 4.x
以后的版本,body-parser
已经内置于 Express 框架中。
所以,笔者在这里还是将两种方法都写一遍,以免读者使用了 4.x 以前的版本却又不会解析POST
请求
2.1 方式一:内置版
//src/index.js
const express = require("express");
const app = express();
// 使用 express.json() 中间件来解析 JSON 格式的请求体
// 使用 express.urlencoded() 中间件来解析 URL 编码的请求体
app.use(express.json(), express.urlencoded({ extended: true }));
app.use(require("./common/utils/morgan")); // 日志
app.use("/", require("./controller")); // 路由分离
module.exports = app;
2.2 方式二:body-parser
//src/index.js
const express = require("express");
const bodyParser = require("body-parser");
const app = express();
// 解析POST
app.use(bodyParser.json(), bodyParser.urlencoded({ extended: true }));
app.use(require("./common/utils/morgan")); // 日志
app.use("/", require("./controller")); // 路由分离
module.exports = app;
2.3 编写接口
// UserControler.js
UserControler.post("/", async (req, res) => {
res.send(Result.success(await req.body));
});
2.4 校验接口
三、日志中间件
当我们的应用程序连接到数据库并提供了一系列接口后,有时我们可能不太清楚这些接口的具体行为,或者当遇到大量请求时,我们无法确定是哪些IP地址在频繁访问我们的系统。这时,引入日志中间件,如Morgan
,就显得尤为重要。
日志中间件可以帮助我们记录每个请求的详细信息,包括请求的IP地址、请求方法、路径、状态码以及响应时间等。这样,我们不仅能够监控接口的使用情况,还能够在出现问题时快速定位和诊断问题。
通过使用Morgan
,我们可以轻松地为Express.js应用程序添加日志记录功能,从而提高系统的可维护性和安全性。
安装 Morgan
npm i morgan
使用
//src/common/utils/morgan.js
const morgan = require("morgan");
// 请求IP 方法 状态 路径 响应时间
module.exports = morgan(
":remote-addr :method :status :url :response-time ms"
);
这里需要注意,日志中间件的导入需要在路由前,Express
的设计是一层层的,往下走,而中间件的使用顺序就在此尤为重要了
//src/index.js
const app = require("express")();
app.use(require("./common/utils/morgan")); // 日志
app.use("/", require("./controller")); // 路由分离
module.exports = app;
结语
至此,我们成功构建了一个集成了MySQL
、Knex
和Morgan
的后端简易开发系统。该系统不仅体现了Express
框架的轻量级和灵活性,还借助强大的中间件生态实现了更多高级功能。受限于篇幅和笔者的技术水平,我们无法对所有的中间件和框架原理进行详尽的解析,但本文旨在为所有对Express
框架感兴趣的读者提供一个清晰、简洁的入门指南。
对于希望快速构建项目原型的读者,本文提供了实用的指导;我相信,通过本文的学习,你将能够初步掌握Express
框架的使用方法,并在实践中不断提升自己的技能。
为了让你更深入地了解本项目的实现细节和代码结构,我已将项目代码上传至Gitee平台。如果你对项目有任何疑问,或者想要下载代码进行学习,都可以前往Gitee进行查看和下载。同时,我也非常期待你的反馈和建议,若是你有任何好的思路或想法,欢迎在Gitee、评论区、私信等方式与我进行探讨和交流。
感谢你的阅读、点赞和关注,希望你在Express框架的学习道路上越走越远,不断取得新的进步!