Express
Express 是运行在 Node.js 之上的极简 Web 框架,提供路由、中间件与 HTTP 工具。见 后端入门概览、EJS。
一、Express 基础概念
- 什么是 Express:Node.js 中最流行的 Web 开发框架,基于 Node.js 原生 HTTP 模块构建,提供了路由、中间件、模板引擎等核心能力,被用于构建 RESTful API、Web 网站、单页应用(SPA)后端等开发场景。
- 核心特点:
- 极简而灵活,开发者可以根据需求组合中间件和工具
- 基于中间件架构,处理请求的生命周期被拆分为多个可插拔的函数
- 强大的路由系统,支持参数、正则表达式、模块化路由
- 内置错误处理,便于进行异步和同步错误的统一管理
- 与各种模板引擎(如 EJS、Pug)无缝集成
- Express vs Node.js 原生 HTTP:Express 在 Node.js 的 http 模块之上做了封装,提供了更便捷的 API,降低了直接处理请求、路由匹配和响应处理的复杂度。
二、安装与环境
1. 安装 Express
# 创建项目目录并初始化
mkdir my-app && cd my-app
npm init -y
# 安装 Express
npm install express
2. 最小可用示例
const express = require("express");
const app = express();
const port = 3000;
app.get("/", (req, res) => {
res.send("Hello World!");
});
app.listen(port, () => {
console.log(`服务器运行在 http://localhost:${port}`);
});
3. 开启开发模式(自动重启)
安装 nodemon:
npm install -D nodemon
在 package.json 中添加脚本:
{
"scripts": {
"dev": "nodemon app.js"
}
}
运行 npm run dev 即可在代码变更后自动重启服务器。
三、请求对象(Request Object)
请求对象(req)包含了客户端发送的所有 HTTP 请求信息,是应用处理请求的重要依据。
| 属性/方法 | 说明 | 示例 |
|---|---|---|
req.params | 获取路由路径中的动态参数 | req.params.id(路由 /:id) |
req.query | 获取 URL 查询字符串参数 | req.query.page(?page=2) |
req.body | 获取 POST/PUT 请求体中的参数 | req.body.username(需配合中间件) |
req.headers | 获取客户端发送的 HTTP 头信息 | req.headers['content-type'] |
req.method | 获取 HTTP 请求方法 | GET, POST, PUT, DELETE 等 |
req.url | 获取请求的 URL 路径 | /api/users |
各属性的详细用法:
// 路由参数 params: GET /user/123 -> { id: '123' }
app.get("/user/:id", (req, res) => {
console.log(req.params.id);
});
// 查询参数 query: GET /search?q=express&page=1 -> { q: 'express', page: '1' }
app.get("/search", (req, res) => {
console.log(req.query.q);
});
// 请求体 body: 需要 express.json() 或 express.urlencoded() 中间件
app.post("/login", (req, res) => {
console.log(req.body.username);
});
// 请求头 headers
app.get("/info", (req, res) => {
console.log(req.headers["user-agent"]);
});
注意:若要使用
req.body,必须先应用解析请求体的中间件,如express.json()或express.urlencoded()。
四、响应对象(Response Object)
响应对象(res)用于向客户端返回数据。以下是最常用的响应方法:
| 方法 | 说明 | 示例 |
|---|---|---|
res.send() | 发送各种类型的响应(字符串、对象、Buffer 等) | res.send('Hello') |
res.json() | 发送 JSON 格式响应,自动设置 Content-Type: application/json | res.json({ name: 'John' }) |
res.status() | 设置 HTTP 状态码,支持链式调用 | res.status(201).send('Created') |
res.redirect() | 重定向到指定 URL | res.redirect('/login') |
res.render() | 渲染模板引擎(需配置) | res.render('index', { title: '主页' }) |
res.sendFile() | 发送文件(用于文件下载) | res.sendFile(path.join(__dirname, 'file.pdf')) |
res.sendStatus() | 设置状态码并发送其对应的文本描述 | res.sendStatus(404)→'Not Found' |
各方法的详细用法:
// 发送纯文本
app.get("/", (req, res) => {
res.send("Hello World!");
});
// 发送 JSON
app.get("/api/user", (req, res) => {
res.json({ id: 1, name: "Alice" });
});
// 链式调用:先设置状态码,再发送响应
app.post("/api/user", (req, res) => {
res.status(201).json({ message: "用户创建成功" });
});
// 重定向
app.get("/old", (req, res) => {
res.redirect("/new");
});
五、路由(Routing)
路由是 Express 的核心功能之一,它将 HTTP 方法、URL 路径与处理函数关联起来。
1. 基本路由
// GET 请求
app.get("/", (req, res) => {
res.send("收到 GET 请求");
});
// POST 请求
app.post("/user", (req, res) => {
res.send("收到 POST 请求");
});
// PUT 请求
app.put("/user/:id", (req, res) => {
res.send(`更新用户 ${req.params.id}`);
});
// DELETE 请求
app.delete("/user/:id", (req, res) => {
res.send(`删除用户 ${req.params.id}`);
});
// 处理所有 HTTP 方法(常用于全局中间件)
app.all("/secret", (req, res, next) => {
console.log("访问了秘密路径");
next();
});
2. 路由参数
// 单个参数
app.get("/users/:userId", (req, res) => {
res.send(`用户 ID: ${req.params.userId}`);
});
// 多个参数
app.get("/posts/:postId/comments/:commentId", (req, res) => {
res.send(`帖子 ${req.params.postId},评论 ${req.params.commentId}`);
});
3. express.Router 模块化路由(推荐用于项目结构)
随着应用规模增长,将所有路由写在同一个文件中会导致代码难以维护。express.Router 允许将相关的路由分组并导出,实现代码的模块化。
// routes/users.js 文件
const express = require("express");
const router = express.Router();
// 该路由下的中间件(仅对此模块生效)
router.use((req, res, next) => {
console.log(`[Users] ${req.method} ${req.path}`);
next();
});
router.get("/", (req, res) => {
res.json({ users: ["Alice", "Bob"] });
});
router.get("/:id", (req, res) => {
res.json({ userId: req.params.id });
});
router.post("/", (req, res) => {
res.status(201).json({ message: "用户创建成功" });
});
module.exports = router;
// app.js 主文件
const express = require("express");
const userRoutes = require("./routes/users");
const app = express();
app.use(express.json());
// 挂载路由:所有以 /api/users 开头的请求都会进入 userRoutes
app.use("/api/users", userRoutes);
app.listen(3000);
六、中间件(Middleware)
中间件是 Express 的核心理念。一个中间件函数可以访问 req、res 和 next,它可以在请求到达最终处理函数之前/之后执行各类逻辑,如日志记录、身份验证、请求解析等。
1. 中间件的执行流程
const express = require("express");
const app = express();
// 中间件1:记录日志
app.use((req, res, next) => {
console.log(`${req.method} ${req.url} - ${new Date().toISOString()}`);
next(); // 调用 next() 将控制权交给下一个中间件
});
// 中间件2:添加自定义属性
app.use((req, res, next) => {
req.requestTime = Date.now();
next();
});
// 路由处理函数
app.get("/", (req, res) => {
res.send(`请求时间: ${req.requestTime}`);
});
app.listen(3000);
2. 中间件的常见类型
- 应用级中间件:通过
app.use()、app.METHOD()绑定到app对象 - 路由级中间件:绑定到
express.Router()实例,语法与应用级中间件相同 - 内置中间件:Express 自带的中间件,如
express.json()、express.urlencoded()、express.static() - 第三方中间件:通过 npm 安装的中间件,如
cors、helmet、morgan
各类型中间件的详细使用方式:
// 应用级中间件(全局生效)
app.use((req, res, next) => {
console.log("所有请求都会经过这里");
next();
});
// 路由级中间件(仅对该路径生效)
app.use("/api/protected", (req, res, next) => {
const token = req.headers.authorization;
if (!token) {
return res.status(401).json({ error: "未授权" });
}
next();
});
// 内置中间件:解析 JSON 请求体
app.use(express.json());
// 内置中间件:解析 URL-encoded 表单数据
app.use(express.urlencoded({ extended: true }));
// 内置中间件:托管静态文件
app.use(express.static("public"));
// 第三方中间件示例:CORS
const cors = require("cors");
app.use(cors());
// 第三方中间件示例:安全头
const helmet = require("helmet");
app.use(helmet());
// 第三方中间件示例:Morgan 日志
const morgan = require("morgan");
app.use(morgan("dev"));
3. 中间件的执行顺序
中间件的加载顺序决定了执行的先后顺序。先加载的中间件先执行:
// ❌ 错误顺序:路由在前,中间件在后
app.get("/", (req, res) => res.send("Hello"));
app.use(logger); // logger 永远不会执行
// ✅ 正确顺序:先加载全局中间件,后加载路由
app.use(logger);
app.get("/", (req, res) => res.send("Hello"));
app.use(notFoundHandler); // 404 处理应放在最后
app.use(errorHandler); // 错误处理应放在最后
重要:
next()是中间件链的“通行证”。如果不调用next()且没有结束响应(如用res.send()),请求将被挂起,直到超时。
七、错误处理
Express 内置了一个默认的错误处理程序,同时支持自定义错误处理中间件。错误处理中间件与普通中间件的唯一区别是四个参数:(err, req, res, next)。
1. 同步错误
Express 会自动捕获同步代码中抛出的错误:
app.get("/", (req, res) => {
throw new Error("出错了!"); // Express 会自动捕获
});
2. 异步错误
异步错误必须通过 next() 传递给 Express。在 Express 5 中,返回 Promise 的异步函数若拒绝,会自动调用 next:
// Express 4 及以下:需要手动传递
app.get("/file", (req, res, next) => {
fs.readFile("/some-file", (err, data) => {
if (err) {
next(err); // 将错误传递给 Express
} else {
res.send(data);
}
});
});
// Express 5:自动处理 Promise/promise reject
app.get("/user/:id", async (req, res, next) => {
const user = await getUserById(req.params.id);
res.send(user); // 如果 getUserById 抛出异常,Express 会自动调用 next
});
3. 自定义错误处理中间件
必须定义在所有路由之后,并声明四个参数:
// 普通路由
app.get("/", (req, res) => {
res.send("Hello");
});
// 404 处理(没有匹配到任何路由时)
app.use((req, res, next) => {
res.status(404).json({ error: "请求的资源不存在" });
});
// 全局错误处理中间件(放在最后)
app.use((err, req, res, next) => {
console.error("错误信息:", err.stack);
res.status(500).json({ error: "服务器内部错误" });
});
八、常用中间件速查表
| 中间件 | 用途 | 安装命令 |
|---|---|---|
express.json() | 解析 JSON 格式请求体 | 内置,无需安装 |
express.urlencoded() | 解析表单数据(URL-encoded) | 内置,无需安装 |
express.static() | 托管静态文件 | 内置,无需安装 |
cors | 处理跨域资源共享 | npm install cors |
helmet | 设置安全 HTTP 头,防御常见 Web 漏洞 | npm install helmet |
morgan | HTTP 请求日志记录 | npm install morgan |
compression | Gzip 压缩响应内容 | npm install compression |
express-rate-limit | 限制重复请求频率(防暴力 / DDoS) | npm install express-rate-limit |
cookie-parser | 解析 Cookie | npm install cookie-parser |
参考文献
以下链接在编写时均可正常访问:
| 资料 | 说明 |
|---|---|
| Express 指南 | 路由 |
| Express 5 迁移 | 版本说明 |
| Node.js http | 底层模块 |
相关文章
后端入门概览
本目录覆盖 JavaScript/TypeScript 服务端运行时与框架、数据存储,以及 Rust 系统编程入门,提供从零到部署的完整学习路径。前置建议:JavaScript 基础、工程化 · 环境变量。
Bun 基础与核心命令
Bun 是用 Zig 编写的 JavaScript 运行时,内置包管理(bun install)、打包(bun build)、测试(bun test)等,并持续兼容 Node.js API。本文介绍核心特点、安装方式,以及日常最常用的命令与包管理功能。见 运行时对比。
HTTP 服务器
Bun 内置了高性能的 HTTP 服务器,通过 Bun.serve 可以轻松启动服务。从 Bun v1.2.3 开始,推荐使用 routes 对象来定义路由,更加直观和灵活。
文件系统
Node.js 的 fs 模块提供了与文件系统交互的 API,几乎涵盖了所有标准文件操作。它支持三种风格的 API:同步、回调式异步 和 Promise 式异步。下面详细介绍这些 API 的选择策略、流式读写、文件监视以及常用操作。
Deno 基础
Deno 是基于 V8 与 Rust 的 JavaScript/TypeScript 运行时,由 Node.js 原作者 Ryan Dahl 发起。官方文档:docs.deno.com。与 Node、Bun 的对比见 运行时对比。
异常处理器