Express.js 基础
后端框架 Express.js HTTP一、什么是 Express.js
1.1 定义
Express 是构建在 Node.js 之上的 Web 应用框架,专门用于创建网站后端。
Node.js 是运行时环境(允许 JS 在浏览器外运行),Express 是框架(简化 Web 后端开发)。
1.2 为什么用 Express
javascript
// 纯 Node.js — 创建简单网站需要大量代码
const http = require('http');
const server = http.createServer((req, res) => {
if (req.url === '/') { /* ... 复杂处理 ... */ }
if (req.url === '/about') { /* ... */ }
});
// Express — 简洁清晰
app.get("/", (req, res) => { res.send("Home"); });
app.get("/about", (req, res) => { res.send("About"); });| 优势 | 说明 |
|---|---|
| 代码更少 | 大幅简化路由、请求处理 |
| 可读性强 | 模块化、直观的 API |
| 中间件系统 | 像乐高一样组装功能 |
| 最流行 | State of JS 中 Node 后端框架 #1 |
类比:Node.js 是螺丝刀(通用工具),Express 是电动螺丝刀(专门为组装 Web 后端加速)。
二、创建 Express 服务器(6 步)
2.1 完整流程
bash
# 1. 创建项目目录
mkdir my-express-server
# 2. 进入目录,创建入口文件
cd my-express-server
touch index.js
# 3. 初始化 NPM
npm init -y
# 4. 安装 Express
npm i express
# 5. 配置 ESM(在 package.json 中)
# 添加 "type": "module"
# 6. 编写代码 + 启动服务器
node index.js2.2 最小服务器代码
javascript
import express from "express";
const app = express();
const port = 3000;
app.listen(port, () => {
console.log(`Server running on port ${port}`);
});2.3 localhost 与端口
https://localhost:3000
↑ ↑
本机服务器 端口号(门)- localhost = 本机作为服务器(开发/测试用)
- 端口 = 服务器上的"门",不同服务监听不同端口
- 常用端口:3000、5000、8080
bash
# 查看占用端口(Mac)
sudo lsof -i -P -n | grep LISTEN
# 查看占用端口(Windows)
netstat -ano | findstr "LISTENING"端口冲突
如果看到 EADDRINUSE 错误,说明端口被占用:
- 找到并关闭已启动的服务器(
Ctrl + C) - 或杀死对应进程
三、HTTP 请求方法
3.1 五个核心方法
| 方法 | 功能 | 类比 |
|---|---|---|
| GET | 获取资源 | 从图书馆借书 |
| POST | 发送/创建资源 | 向图书馆捐书 |
| PUT | 完整替换资源 | Amazon 直接换一辆新自行车 |
| PATCH | 部分更新资源 | Amazon 只寄一个新轮胎来修 |
| DELETE | 删除资源 | 从书架上撤掉一本书 |
3.2 Express 路由处理
javascript
// GET — 首页
app.get("/", (req, res) => {
res.send("<h1>Home Page</h1>");
});
// GET — 关于页
app.get("/about", (req, res) => {
res.send("<h1>About Me</h1><p>My name is Hugo</p>");
});
// POST — 注册
app.post("/register", (req, res) => {
res.sendStatus(201); // 201 Created
});
// PUT — 替换用户数据
app.put("/user/angela", (req, res) => {
res.sendStatus(200);
});
// PATCH — 部分更新
app.patch("/user/angela", (req, res) => {
res.sendStatus(200);
});
// DELETE — 删除用户
app.delete("/user/angela", (req, res) => {
res.sendStatus(200);
});3.3 请求与响应对象
javascript
app.get("/", (req, res) => {
// req — 请求对象(来自客户端的信息)
console.log(req.rawHeaders); // 请求头
console.log(req.method); // "GET"
console.log(req.url); // "/"
// res — 响应对象(发回客户端的信息)
res.send("Hello World"); // 发送文本
res.send("<h1>Hello</h1>"); // 发送 HTML
res.sendStatus(200); // 发送状态码
res.sendFile(absolutePath); // 发送文件
res.redirect("/"); // 重定向
});四、HTTP 状态码
4.1 五大类别
| 范围 | 含义 | 通俗版 |
|---|---|---|
| 1xx | 信息性 | "稍等,处理中…" |
| 2xx | 成功 | "给你,搞定了!" |
| 3xx | 重定向 | "去别的地方找" |
| 4xx | 客户端错误 | "你搞错了" |
| 5xx | 服务器错误 | "我搞错了" |
4.2 常见状态码
| 状态码 | 含义 | 常见场景 |
|---|---|---|
200 | OK | GET 请求成功 |
201 | Created | POST/PUT 创建成功 |
301 | Moved Permanently | URL 永久改变,重定向 |
404 | Not Found | 请求的资源不存在 |
500 | Internal Server Error | 服务器内部错误 |
五、Postman 测试工具
5.1 为什么需要 Postman
- 无需编写前端 HTML 即可测试后端 API
- 可以模拟所有类型的 HTTP 请求(GET/POST/PUT/PATCH/DELETE)
- 可以设置请求体(Body)、请求头(Headers)等
5.2 基本用法
- 选择请求方法(GET/POST 等)
- 输入 URL(如
localhost:3000/register) - 设置 Body(POST/PUT 时)→ 选
x-www-form-urlencoded - 点击 Send → 查看响应状态码和内容
六、中间件(Middleware)
6.1 概念
中间件 = 请求到达路由处理器 之前 执行的函数。
客户端请求 → [中间件1] → [中间件2] → [路由处理器] → 响应四大用途:
| 类型 | 功能 | 示例 |
|---|---|---|
| 预处理 | 解析请求体 | body-parser |
| 日志 | 记录请求信息 | Morgan |
| 认证 | 验证用户身份 | passport.js |
| 错误处理 | 捕获并处理错误 | 自定义错误中间件 |
6.2 body-parser — 解析表单数据
javascript
import bodyParser from "body-parser";
// 注册中间件(在路由之前!)
app.use(bodyParser.urlencoded({ extended: true }));
// 现在 req.body 可用
app.post("/submit", (req, res) => {
console.log(req.body);
// { street: "Aberdeen", pet: "Rabbit" }
});💡 Express 4.16+ 内置了 body-parser,可以直接用
express.urlencoded({ extended: true })替代。
6.3 Morgan — 请求日志
javascript
import morgan from "morgan";
app.use(morgan("tiny"));
// 输出: GET / 200 5 - 3.451 msMorgan 的日志格式:
| 格式 | 详细程度 |
|---|---|
combined | 最详细(含 User-Agent 等) |
common | Apache 标准格式 |
dev | 彩色开发日志 |
short | 较短 |
tiny | 最简(方法 + URL + 状态 + 耗时) |
6.4 自定义中间件
javascript
// 定义中间件函数
function logger(req, res, next) {
console.log(`Request Method: ${req.method}`);
console.log(`Request URL: ${req.url}`);
next(); // ← 必须调用!否则请求会挂起
}
// 注册
app.use(logger);next() 至关重要
不调用 next() → 请求永远不会到达路由处理器 → 浏览器一直转圈加载。
6.5 中间件顺序
中间件按 代码顺序 执行,顺序错误会导致问题:
javascript
// ✅ 正确顺序:先解析,再处理
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bandNameGenerator); // 依赖 req.body
// ❌ 错误顺序:req.body 还是 undefined
app.use(bandNameGenerator); // req.body 不存在!
app.use(bodyParser.urlencoded({ extended: true }));七、Nodemon — 自动重启
7.1 安装与使用
bash
# 全局安装
npm i -g nodemon
# 使用 nodemon 代替 node
nodemon index.js
# 文件变化时自动重启服务器对比:
node index.js→ 每次改代码都要Ctrl+C再重启nodemon index.js→ 自动检测文件变化并重启
八、发送文件(res.sendFile)
8.1 获取目录路径
javascript
import { dirname } from "path";
import { fileURLToPath } from "url";
const __dirname = dirname(fileURLToPath(import.meta.url));8.2 发送 HTML 文件
javascript
app.get("/", (req, res) => {
res.sendFile(__dirname + "/public/index.html");
});
res.sendFile仅用于 静态文件。动态模板需要用res.render(EJS)。
九、完整项目示例 — Secrets Access
javascript
import express from "express";
import bodyParser from "body-parser";
import { dirname } from "path";
import { fileURLToPath } from "url";
const __dirname = dirname(fileURLToPath(import.meta.url));
const app = express();
const port = 3000;
let userIsAuthorised = false;
app.use(bodyParser.urlencoded({ extended: true }));
// 自定义中间件:密码验证
function passwordCheck(req, res, next) {
const password = req.body["password"];
if (password === "ILoveProgramming") {
userIsAuthorised = true;
}
next();
}
app.use(passwordCheck);
// GET 首页
app.get("/", (req, res) => {
res.sendFile(__dirname + "/public/index.html");
});
// POST 验证
app.post("/check", (req, res) => {
if (userIsAuthorised) {
res.sendFile(__dirname + "/public/secret.html");
} else {
res.redirect("/");
}
});
app.listen(port, () => {
console.log(`Listening on port ${port}`);
});