跳到主要内容

Express 框架

Express 是 Node.js 最流行的 Web 框架,提供了一系列强大的功能来帮助快速创建 Web 应用和 API。

快速开始

安装

# 创建项目
mkdir my-express-app
cd my-express-app

# 初始化
npm init -y

# 安装 Express
npm install express

基本应用

const express = require('express');

const app = express();
const PORT = 3000;

// 定义路由
app.get('/', (req, res) => {
res.send('Hello, Express!');
});

// 启动服务器
app.listen(PORT, () => {
console.log(`服务器运行在 http://localhost:${PORT}`);
});

Express 应用生成器

# 安装生成器
npm install -g express-generator

# 创建项目
express my-app

# 安装依赖
cd my-app
npm install

# 启动
npm start

路由

基本路由

const express = require('express');
const app = express();

// GET 请求
app.get('/', (req, res) => {
res.send('GET 请求');
});

// POST 请求
app.post('/', (req, res) => {
res.send('POST 请求');
});

// PUT 请求
app.put('/', (req, res) => {
res.send('PUT 请求');
});

// DELETE 请求
app.delete('/', (req, res) => {
res.send('DELETE 请求');
});

// 匹配所有 HTTP 方法
app.all('/secret', (req, res) => {
res.send('访问秘密区域');
});

路由参数

// 路径参数
app.get('/users/:id', (req, res) => {
res.send(`用户 ID: ${req.params.id}`);
});

// 多个路径参数
app.get('/users/:userId/books/:bookId', (req, res) => {
res.send(`用户 ${req.params.userId} 的书 ${req.params.bookId}`);
});

// 可选参数
app.get('/users/:id?', (req, res) => {
if (req.params.id) {
res.send(`用户 ID: ${req.params.id}`);
} else {
res.send('所有用户');
}
});

// 正则表达式
app.get('/users/:id(\\d+)', (req, res) => {
res.send(`数字 ID: ${req.params.id}`);
});

查询参数

app.get('/search', (req, res) => {
const { q, page, limit } = req.query;
res.json({
query: q,
page: page || 1,
limit: limit || 10
});
});

// 访问 /search?q=nodejs&page=2
// 响应: { query: "nodejs", page: "2", limit: 10 }

路由方法

// 路由路径可以是字符串模式
app.get('/ab?cd', (req, res) => {
// 匹配 acd 或 abcd
res.send('ab?cd');
});

app.get('/ab+cd', (req, res) => {
// 匹配 abcd, abbcd, abbbcd...
res.send('ab+cd');
});

app.get('/ab*cd', (req, res) => {
// 匹配 abcd, abANYcd, ab123cd...
res.send('ab*cd');
});

app.get('/ab(cd)?e', (req, res) => {
// 匹配 abe 或 abcde
res.send('ab(cd)?e');
});

// 正则表达式路由
app.get(/a/, (req, res) => {
// 匹配任何包含 'a' 的路径
res.send('/a/');
});

中间件

中间件是 Express 的核心概念,用于处理请求和响应。

应用级中间件

const express = require('express');
const app = express();

// 全局中间件
app.use((req, res, next) => {
console.log(`${req.method} ${req.url} - ${new Date().toISOString()}`);
next(); // 调用下一个中间件
});

// 路由级中间件
app.use('/api', (req, res, next) => {
console.log('API 请求');
next();
});

// 错误处理中间件
app.use((err, req, res, next) => {
console.error(err.stack);
res.status(500).send('服务器错误');
});

内置中间件

const express = require('express');
const app = express();

// 解析 JSON 请求体
app.use(express.json());

// 解析 URL 编码的请求体
app.use(express.urlencoded({ extended: true }));

// 提供静态文件
app.use(express.static('public'));
app.use('/static', express.static('public'));

// 安全相关的中间件
app.use(express.static('public', {
dotfiles: 'ignore',
etag: false,
extensions: ['htm', 'html'],
index: false,
maxAge: '1d',
redirect: false,
setHeaders: function (res, path, stat) {
res.set('x-timestamp', Date.now());
}
}));

路由级中间件

const express = require('express');
const router = express.Router();

// 路由级中间件
router.use((req, res, next) => {
console.log('路由中间件');
next();
});

// 单个路由的中间件
router.get('/user/:id',
(req, res, next) => {
if (req.params.id === '0') next('route');
else next();
},
(req, res) => {
res.send('普通用户');
}
);

router.get('/user/:id', (req, res) => {
res.send('特殊用户');
});

app.use('/api', router);

第三方中间件

const express = require('express');
const cors = require('cors');
const helmet = require('helmet');
const morgan = require('morgan');
const compression = require('compression');

const app = express();

// CORS
app.use(cors({
origin: ['https://example.com'],
methods: ['GET', 'POST'],
credentials: true
}));

// 安全头
app.use(helmet());

// 日志
app.use(morgan('combined'));

// 压缩响应
app.use(compression());

请求和响应

Request 对象

app.get('/info', (req, res) => {
res.json({
method: req.method, // 请求方法
url: req.url, // 请求 URL
path: req.path, // 请求路径
query: req.query, // 查询参数
params: req.params, // 路径参数
headers: req.headers, // 请求头
body: req.body, // 请求体(需要解析中间件)
cookies: req.cookies, // Cookies(需要 cookie-parser)
ip: req.ip, // 客户端 IP
protocol: req.protocol, // 协议
hostname: req.hostname, // 主机名
xhr: req.xhr, // 是否 AJAX 请求
});
});

Response 对象

// 发送文本
res.send('Hello');

// 发送 JSON
res.json({ message: '成功' });

// 发送状态码
res.status(201).json({ created: true });

// 发送文件
res.sendFile('/path/to/file.pdf');

// 下载文件
res.download('/path/to/file.pdf', 'report.pdf');

// 重定向
res.redirect('/home');
res.redirect(301, '/new-home');

// 设置响应头
res.set('Content-Type', 'text/plain');
res.set('X-Custom-Header', 'value');

// 设置 Cookie
res.cookie('name', 'value', {
maxAge: 900000,
httpOnly: true
});

// 清除 Cookie
res.clearCookie('name');

// 发送状态码
res.sendStatus(200); // 等同于 res.status(200).send('OK')
res.sendStatus(404); // 等同于 res.status(404).send('Not Found')

路由模块化

创建路由模块

// routes/users.js
const express = require('express');
const router = express.Router();

// 中间件
router.use((req, res, next) => {
console.log('用户路由');
next();
});

// 路由
router.get('/', (req, res) => {
res.json({ users: [] });
});

router.get('/:id', (req, res) => {
res.json({ id: req.params.id });
});

router.post('/', (req, res) => {
res.status(201).json(req.body);
});

module.exports = router;

使用路由模块

// app.js
const express = require('express');
const usersRouter = require('./routes/users');
const postsRouter = require('./routes/posts');

const app = express();

app.use(express.json());

// 挂载路由
app.use('/users', usersRouter);
app.use('/posts', postsRouter);

app.listen(3000);

错误处理

错误处理中间件

const express = require('express');
const app = express();

// 自定义错误类
class AppError extends Error {
constructor(message, statusCode) {
super(message);
this.statusCode = statusCode;
this.isOperational = true;
Error.captureStackTrace(this, this.constructor);
}
}

// 404 处理
app.use((req, res, next) => {
next(new AppError(`找不到 ${req.originalUrl}`, 404));
});

// 全局错误处理
app.use((err, req, res, next) => {
err.statusCode = err.statusCode || 500;
err.status = err.status || 'error';

if (process.env.NODE_ENV === 'development') {
res.status(err.statusCode).json({
status: err.status,
error: err,
message: err.message,
stack: err.stack
});
} else {
res.status(err.statusCode).json({
status: err.status,
message: err.message
});
}
});

异步错误处理

// Express 5 自动处理异步错误
app.get('/async', async (req, res, next) => {
const data = await getData(); // 如果抛出错误,自动传递给错误处理
res.json(data);
});

// Express 4 需要手动传递
app.get('/async', async (req, res, next) => {
try {
const data = await getData();
res.json(data);
} catch (err) {
next(err);
}
});

// 或使用包装函数
const catchAsync = (fn) => {
return (req, res, next) => {
fn(req, res, next).catch(next);
};
};

app.get('/async', catchAsync(async (req, res) => {
const data = await getData();
res.json(data);
}));

完整示例

RESTful API

const express = require('express');
const app = express();

// 中间件
app.use(express.json());

// 模拟数据库
let users = [
{ id: 1, name: 'Alice', email: '[email protected]' },
{ id: 2, name: 'Bob', email: '[email protected]' }
];

// 获取所有用户
app.get('/users', (req, res) => {
res.json({ data: 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({ error: '用户不存在' });
}
res.json({ data: user });
});

// 创建用户
app.post('/users', (req, res) => {
const { name, email } = req.body;

if (!name || !email) {
return res.status(400).json({ error: 'name 和 email 是必填项' });
}

const user = {
id: users.length + 1,
name,
email
};

users.push(user);
res.status(201).json({ data: user });
});

// 更新用户
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({ error: '用户不存在' });
}

users[index] = { ...users[index], ...req.body };
res.json({ data: 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({ error: '用户不存在' });
}

users.splice(index, 1);
res.status(204).send();
});

// 错误处理
app.use((err, req, res, next) => {
console.error(err.stack);
res.status(500).json({ error: '服务器错误' });
});

app.listen(3000, () => {
console.log('服务器运行在 http://localhost:3000');
});

小结

本章我们学习了:

  1. Express 基础:安装、创建应用、路由定义
  2. 路由:路径参数、查询参数、路由方法
  3. 中间件:应用级、路由级、内置中间件
  4. 请求响应:Request 和 Response 对象
  5. 路由模块化:拆分路由文件
  6. 错误处理:自定义错误、异步错误

练习

  1. 创建一个完整的 RESTful API,包含 CRUD 操作
  2. 实现用户认证中间件(JWT)
  3. 创建一个文件上传接口
  4. 实现请求日志和错误追踪