Node.js Express 框架

路由、中间件、错误处理、参数校验——Express 的四件事。

Intermediate
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
KindSignatureExample
应用级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 morgan
JavaScript
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' })); // 限制体积

参数在哪

SourceAccess
路径参数 /u/:idreq.params.id
查询串 ?a=1req.query.a
JSON / 表单体req.body
请求头req.get('X-Token')
Cookiereq.cookies.x(需 cookie-parser)

Friends & Partners