Node.js Express 框架
路由、中间件、错误处理、参数校验——Express 的四件事。
Key PointsExpress 的核心只有一条:请求依次穿过中间件链,谁先响应谁结束。
最小应用
JavaScript
const express = require('express');
const app = express();
app.use(express.json());
app.get('/', (req, res) => res.send('Hello'));
app.listen(3000, () => console.log('http://127.0.0.1:3000'));中间件链
JavaScript
// 顺序很重要:注册在前面的先执行
app.use((req, res, next) => {
req.startAt = Date.now();
console.log('→', req.method, req.url);
next(); // 不调 next 请求就停在这里
});
app.use((req, res, next) => {
res.on('finish', () => {
console.log('←', res.statusCode, Date.now() - req.startAt, 'ms');
});
next();
});Output
→ GET /api/users
← 200 12 ms| Kind | Signature | Example |
|---|---|---|
| 应用级 | app.use(fn) | 日志、CORS |
| 路由级 | router.use(fn) | 模块内鉴权 |
| 错误处理 | (err, req, res, next) | 统一异常 |
| 内置 | express.json() 等 | 解析请求体 |
| 第三方 | cors() helmet() | 安全头、跨域 |
路由分组
JavaScript
const router = express.Router();
router.get('/', (req, res) => res.json([]));
router.get('/:id', (req, res) => res.json({ id: req.params.id }));
router.post('/', (req, res) => res.status(201).json(req.body));
app.use('/api/users', router);错误处理
JavaScript
// 同步抛错会被 Express 自动捕获
app.get('/sync', (req, res) => {
throw new Error('同步错误');
});
// async 函数里的错误必须自己交给 next(Express 4)
app.get('/async', async (req, res, next) => {
try {
const data = await load();
res.json(data);
} catch (e) {
next(e);
}
});
// 错误中间件:四个参数,必须放最后
app.use((err, req, res, next) => {
console.error(err);
res.status(err.status || 500).json({ error: err.message });
});Express 4 does not catch rejections from async handlers — the request hangs until timeout. Either wrap every async handler in
try/catch + next(e), use express-async-errors, or move to Express 5.常用中间件
Bash
npm i express cors helmet morganJavaScript
const cors = require('cors');
const helmet = require('helmet');
const morgan = require('morgan');
app.use(helmet()); // 安全响应头
app.use(cors({ origin: 'https://a.com' })); // 跨域
app.use(morgan('dev')); // 访问日志
app.use(express.json({ limit: '1mb' })); // 限制体积参数在哪
| Source | Access |
|---|---|
路径参数 /u/:id | req.params.id |
查询串 ?a=1 | req.query.a |
| JSON / 表单体 | req.body |
| 请求头 | req.get('X-Token') |
| Cookie | req.cookies.x(需 cookie-parser) |
最小应用
JavaScript
const express = require('express');
const app = express();
app.use(express.json());
app.get('/', (req, res) => res.send('Hello'));
app.listen(3000, () => console.log('http://127.0.0.1:3000'));中间件链
JavaScript
// 顺序很重要:注册在前面的先执行
app.use((req, res, next) => {
req.startAt = Date.now();
console.log('→', req.method, req.url);
next(); // 不调 next 请求就停在这里
});
app.use((req, res, next) => {
res.on('finish', () => {
console.log('←', res.statusCode, Date.now() - req.startAt, 'ms');
});
next();
});Output
→ GET /api/users
← 200 12 ms| 类型 | 签名 | 例子 |
|---|---|---|
| 应用级 | app.use(fn) | 日志、CORS |
| 路由级 | router.use(fn) | 模块内鉴权 |
| 错误处理 | (err, req, res, next) | 统一异常 |
| 内置 | express.json() 等 | 解析请求体 |
| 第三方 | cors() helmet() | 安全头、跨域 |
路由分组
JavaScript
const router = express.Router();
router.get('/', (req, res) => res.json([]));
router.get('/:id', (req, res) => res.json({ id: req.params.id }));
router.post('/', (req, res) => res.status(201).json(req.body));
app.use('/api/users', router);错误处理
JavaScript
// 同步抛错会被 Express 自动捕获
app.get('/sync', (req, res) => {
throw new Error('同步错误');
});
// async 函数里的错误必须自己交给 next(Express 4)
app.get('/async', async (req, res, next) => {
try {
const data = await load();
res.json(data);
} catch (e) {
next(e);
}
});
// 错误中间件:四个参数,必须放最后
app.use((err, req, res, next) => {
console.error(err);
res.status(err.status || 500).json({ error: err.message });
});Express 4 不会捕获 async 函数里的 rejection,请求会一直挂着直到超时。要么每个
async 处理函数都 try/catch + next(e),要么用 express-async-errors,要么升级到 Express 5。常用中间件
Bash
npm i express cors helmet morganJavaScript
const cors = require('cors');
const helmet = require('helmet');
const morgan = require('morgan');
app.use(helmet()); // 安全响应头
app.use(cors({ origin: 'https://a.com' })); // 跨域
app.use(morgan('dev')); // 访问日志
app.use(express.json({ limit: '1mb' })); // 限制体积参数在哪
| 来源 | 取值 |
|---|---|
路径参数 /u/:id | req.params.id |
查询串 ?a=1 | req.query.a |
| JSON / 表单体 | req.body |
| 请求头 | req.get('X-Token') |
| Cookie | req.cookies.x(需 cookie-parser) |