Skip to content

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.js

2.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 常见状态码

状态码含义常见场景
200OKGET 请求成功
201CreatedPOST/PUT 创建成功
301Moved PermanentlyURL 永久改变,重定向
404Not Found请求的资源不存在
500Internal Server Error服务器内部错误

五、Postman 测试工具

5.1 为什么需要 Postman

  • 无需编写前端 HTML 即可测试后端 API
  • 可以模拟所有类型的 HTTP 请求(GET/POST/PUT/PATCH/DELETE)
  • 可以设置请求体(Body)、请求头(Headers)等

5.2 基本用法

  1. 选择请求方法(GET/POST 等)
  2. 输入 URL(如 localhost:3000/register
  3. 设置 Body(POST/PUT 时)→ 选 x-www-form-urlencoded
  4. 点击 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 ms

Morgan 的日志格式:

格式详细程度
combined最详细(含 User-Agent 等)
commonApache 标准格式
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}`);
});

← 返回 Web 开发研究