一、Node.js 开发模式
Node.js 常见的开发模式主要解决代码组织、复用和扩展性问题,以下是主流模式:
1. 模块化开发(CommonJS/ES 模块)
-
CommonJS :Node.js 默认规范,通过
require()导入、module.exports导出。javascript
运行
// 导出模块(utils.js) exports.add = (a, b) => a + b; // 导入模块(app.js) const { add } = require('./utils'); -
ES 模块 :Node.js 14 + 支持,需在
package.json中设置"type": "module",使用import/export。javascript
运行
// 导出模块(utils.js) export const add = (a, b) => a + b; // 导入模块(app.js) import { add } from './utils.js';
2. MVC 模式(分层架构)
将代码分为Model(数据层)、View(视图层)、Controller(控制层),解耦业务逻辑:
- Model:处理数据(如数据库操作)。
- Controller:接收请求、调用 Model、返回响应。
- View:前端页面(Node.js 后端通常仅返回 JSON,View 层由前端负责)。
plaintext
项目结构示例:
src/
├── models/ // 数据模型(如UserModel.js)
├── controllers/ // 控制器(如UserController.js)
├── routes/ // 路由(如userRoutes.js)
└── app.js // 入口文件
3. 中间件模式(Express/Koa 核心)
通过中间件链式处理请求,实现功能复用(如日志、权限验证),典型的 AOP(面向切面编程)思想。
总结
- 模块化是 Node.js 的基础,大型项目优先用 ES 模块(更符合现代 JS 规范)。
- MVC 模式适合业务复杂的项目,清晰分离数据、逻辑和控制层。
- 中间件模式是 Express/Koa 的核心,灵活处理请求流程。
二、Session(会话管理)
Session 用于在服务器端存储用户会话信息,基于 Cookie 实现状态保持。
1. 工作原理
- 用户登录后,服务器生成唯一 Session ID,存储在服务器(内存 / 数据库 / Redis),并通过 Cookie 返回给客户端。
- 客户端后续请求携带 Session ID,服务器通过 ID 查询会话信息,识别用户。
2. Express 中使用 Session
bash
运行
npm install express-session
javascript
运行
const express = require('express');
const session = require('express-session');
const app = express();
app.use(session({
secret: 'your-secret-key', // 加密密钥(必填)
resave: false, // 不强制保存未修改的Session
saveUninitialized: false, // 不保存未初始化的Session
cookie: { maxAge: 24 * 60 * 60 * 1000 } // Session有效期1天
}));
// 登录接口
app.post('/login', (req, res) => {
const { username } = req.body;
req.session.user = { username }; // 存储用户信息到Session
res.send('登录成功');
});
// 获取用户信息
app.get('/user', (req, res) => {
if (req.session.user) {
res.send(req.session.user);
} else {
res.status(401).send('未登录');
}
});
3. 局限性
- Session 存储在服务器,分布式部署时需共享 Session(如用 Redis 存储)。
- 依赖 Cookie,客户端禁用 Cookie 则失效。
总结
- Session 适合服务端控制用户状态的场景,需注意分布式部署的 Session 共享问题。
- 核心是
express-session中间件,通过req.session操作会话数据。
三、JWT(JSON Web Token)
JWT 是一种无状态的身份验证方案,将用户信息加密存储在客户端 Token 中,无需服务器存储会话。
1. 工作原理
- 用户登录后,服务器生成 JWT(Header.Payload.Signature)返回给客户端。
- 客户端后续请求在 Header 中携带 JWT,服务器验证签名有效性即可识别用户。
2. Express 中使用 JWT
bash
运行
npm install jsonwebtoken express-jwt
javascript
运行
const jwt = require('jsonwebtoken');
const expressJwt = require('express-jwt');
const app = express();
const secretKey = 'your-secret-key';
// 生成JWT
app.post('/login', (req, res) => {
const { username } = req.body;
const token = jwt.sign({ username }, secretKey, { expiresIn: '1h' }); // 有效期1小时
res.send({ token });
});
// 验证JWT(除了/login接口,其他接口需验证)
app.use(expressJwt({ secret: secretKey, algorithms: ['HS256'] }).unless({ path: ['/login'] }));
// 获取用户信息
app.get('/user', (req, res) => {
res.send(req.user); // express-jwt解析后的用户信息
});
// 错误处理(JWT验证失败)
app.use((err, req, res, next) => {
if (err.name === 'UnauthorizedError') {
res.status(401).send('Token无效或过期');
}
});
3. 优缺点
- 优点:无状态,分布式部署友好;无需 Cookie,支持跨域。
- 缺点:Token 无法主动失效(除非服务端维护黑名单);Payload 不宜存储敏感信息(仅 Base64 编码,未加密)。
总结
- JWT 适合前后端分离、分布式系统的身份验证,核心是
jsonwebtoken生成 Token,express-jwt验证 Token。 - 对比 Session:Session 是有状态(服务端存储),JWT 是无状态(客户端存储)。
四、跨域 CORS
跨域是指浏览器因同源策略限制,拒绝执行不同域名 / 端口的请求,CORS(跨域资源共享)是解决跨域的标准方案。
1. 核心概念
- 同源:协议、域名、端口三者相同。
- CORS 响应头 :服务器通过设置响应头允许跨域请求(如
Access-Control-Allow-Origin)。
2. Express 中解决跨域
bash
运行
npm install cors
javascript
运行
const express = require('express');
const cors = require('cors');
const app = express();
// 允许所有域名跨域
app.use(cors());
// 或指定允许的域名
app.use(cors({
origin: 'http://localhost:8080', // 仅允许前端8080端口跨域
credentials: true, // 允许携带Cookie
methods: ['GET', 'POST', 'PUT', 'DELETE'], // 允许的请求方法
allowedHeaders: ['Content-Type', 'Authorization'] // 允许的请求头
}));
3. 简单请求与预检请求
- 简单请求 :GET/POST,请求头仅包含
Accept/Content-Type等,无需预检。 - 预检请求:PUT/DELETE 或自定义请求头,浏览器先发送 OPTIONS 请求,服务器通过后再发送实际请求。
总结
- 跨域的本质是浏览器的同源策略限制,服务端通过 CORS 响应头授权即可解决。
cors中间件简化了跨域配置,生产环境建议指定具体允许的域名(而非*)。
五、连接 MySQL 数据库
Node.js 连接 MySQL 主要使用mysql2库(兼容mysql库,支持 Promise 和事务)。
1. 安装与基本连接
bash
运行
npm install mysql2
javascript
运行
const mysql = require('mysql2/promise'); // 支持Promise
// 创建连接池(推荐,避免频繁创建/关闭连接)
const pool = mysql.createPool({
host: 'localhost',
user: 'root',
password: 'your-password',
database: 'test_db',
waitForConnections: true,
connectionLimit: 10, // 最大连接数
queueLimit: 0
});
// 测试连接
async function testConnection() {
const [rows] = await pool.query('SELECT 1 + 1 AS solution');
console.log(rows[0].solution); // 输出2
}
testConnection();
2. 基本 CRUD 操作
javascript
运行
// 查询数据
async function getUserById(id) {
const [rows] = await pool.query('SELECT * FROM users WHERE id = ?', [id]);
return rows[0];
}
// 插入数据
async function addUser(username, age) {
const [result] = await pool.query('INSERT INTO users (username, age) VALUES (?, ?)', [username, age]);
return result.insertId;
}
// 更新数据
async function updateUser(id, age) {
await pool.query('UPDATE users SET age = ? WHERE id = ?', [age, id]);
}
// 删除数据
async function deleteUser(id) {
await pool.query('DELETE FROM users WHERE id = ?', [id]);
}
3. ORM 框架(Sequelize)
复杂项目推荐用 ORM(对象关系映射)简化数据库操作:
bash
运行
npm install sequelize mysql2
javascript
运行
const { Sequelize, DataTypes } = require('sequelize');
// 初始化Sequelize
const sequelize = new Sequelize('test_db', 'root', 'your-password', {
host: 'localhost',
dialect: 'mysql'
});
// 定义模型
const User = sequelize.define('User', {
username: { type: DataTypes.STRING, allowNull: false },
age: { type: DataTypes.INTEGER }
});
// 同步模型到数据库(创建表)
(async () => {
await sequelize.sync();
// 插入数据
await User.create({ username: '张三', age: 20 });
// 查询数据
const user = await User.findByPk(1);
console.log(user.toJSON());
})();
总结
- 基础使用
mysql2创建连接池,通过query执行 SQL;复杂项目用 Sequelize/TypeORM 等 ORM 框架。 - 注意 SQL 注入问题:使用参数化查询(
?占位符)或 ORM,避免拼接 SQL 字符串。
六、开发接口(RESTful API)
RESTful API 是符合 REST 设计规范的接口,通过 HTTP 方法表达操作语义,结构清晰。
1. RESTful API 设计规范
- 资源命名 :用名词复数(如
/users而非/getUsers)。 - HTTP 方法对应操作 :
- GET:查询资源(
/users查询所有,/users/:id查询单个)。 - POST:创建资源(
/users)。 - PUT:更新资源(
/users/:id)。 - DELETE:删除资源(
/users/:id)。
- GET:查询资源(
- 状态码:200 成功、201 创建成功、400 参数错误、401 未授权、404 资源不存在、500 服务器错误。
2. Express 开发 RESTful API 示例
javascript
运行
const express = require('express');
const app = express();
app.use(express.json()); // 解析JSON请求体
// 模拟数据库
let users = [
{ id: 1, username: '张三', age: 20 },
{ id: 2, username: '李四', age: 22 }
];
// 查询所有用户
app.get('/users', (req, res) => {
res.status(200).json(users);
});
// 查询单个用户
app.get('/users/:id', (req, res) => {
const user = users.find(u => u.id === parseInt(req.params.id));
if (!user) return res.status(404).json({ message: '用户不存在' });
res.status(200).json(user);
});
// 创建用户
app.post('/users', (req, res) => {
const newUser = { id: users.length + 1, ...req.body };
users.push(newUser);
res.status(201).json(newUser);
});
// 更新用户
app.put('/users/:id', (req, res) => {
const index = users.findIndex(u => u.id === parseInt(req.params.id));
if (index === -1) return res.status(404).json({ message: '用户不存在' });
users[index] = { ...users[index], ...req.body };
res.status(200).json(users[index]);
});
// 删除用户
app.delete('/users/:id', (req, res) => {
const index = users.findIndex(u => u.id === parseInt(req.params.id));
if (index === -1) return res.status(404).json({ message: '用户不存在' });
users.splice(index, 1);
res.status(200).json({ message: '删除成功' });
});
app.listen(3000, () => console.log('API服务器启动'));
总结
- RESTful API 强调资源和 HTTP 方法的语义对应,接口设计需简洁、一致。
- 开发流程:解析请求体→操作数据→返回 JSON 响应 + 正确状态码。
整体总结
| 知识点 | 核心作用 | 关键工具 / 库 |
|---|---|---|
| 开发模式 | 代码组织与架构设计 | 模块化、MVC、中间件模式 |
| Session | 服务端会话管理 | express-session |
| JWT | 无状态身份验证 | jsonwebtoken、express-jwt |
| CORS | 解决跨域请求限制 | cors |
| MySQL 连接 | 操作 MySQL 数据库 | mysql2、Sequelize |
| RESTful API | 标准化接口开发 | Express(路由 + 中间件) |