今天状态不好,零零散散学了一天,但最后自己手画了一张对比表,把
use/method/all的区别理清了。
中间件概念很抽象,但核心观点在:use = 中间件(宽松匹配)
method = 路由(精确匹配)
all = 匹配所有方法,但路径匹配规则介于两者之间
一、今日核心代码(中间件 vs 路由)
app级中间件(use / method / all)
javascript
const express = require('express');
const app = express();
const port = 3000;
// use:不区分方法,路径前缀匹配,通常做预处理
app.use((req, res, next) => {
console.log('第一个中间件');
next();
});
app.use('/user', (req, res, next) => {
console.log('user 前缀的请求都会进来');
next();
});
// method:精确匹配路径 + 指定 HTTP 方法,做最终响应
app.get('/', (req, res, next) => {
console.log('GET / 路由');
res.send('首页');
});
app.post('/', (req, res, next) => {
console.log('POST / 路由');
res.send('提交成功');
});
// all:匹配所有方法,路径必须完全相等(除非有路径参数)
app.all('/secret', (req, res, next) => {
console.log('任何方法访问 /secret 都会进来');
next();
}, (req, res) => {
res.send('secret 页面');
});
app.listen(port);
二、手画的对比表
| 对比项 | use(中间件) | method(get/post/put/delete) | all |
|---|---|---|---|
| 路径匹配 | 前缀匹配(/user 匹配 /user/login) | 精确匹配(/user 只匹配 /user) | 精确匹配(同 method) |
| 方法 | 不区分 GET/POST | 区分 | 不区分(同 use) |
是否必须调用 next() | 通常需要(否则卡住) | 通常不需要(用 res.send 结束) | 看情况 |
| 典型用途 | 日志、解析 body、权限校验 | 具体业务逻辑(登录、注册) | 特殊路径(如 /secret) |
| 第一个参数路径 | 可省略(默认 /) | 不可省略 | 不可省略 |
| 多个中间件合并 | ✅ 逗号分隔 | ✅ 逗号分隔 | ✅ 逗号分隔 |
总结:
昨天的分离写法(userRouter)就是今天“路由”概念的具体实现。
路由 = 处理具体业务(登录、注册、获取动态)
中间件 = 在路由之前/之后做通用处理(打日志、校验登录、解析 JSON)
三、今天踩的坑 + 解决
坑 1:next() 和 res.send() 冲突
javascript
// ❌ 错误写法
app.use((req, res, next) => {
next();
res.send('结束'); // 冲突:一个请求不能结束两次
});
规则:一个请求生命周期内,res.send / res.json / res.end 只能调用一次。
next() 之后不要再调用这些结束方法。
坑 2:端口冲突 + 僵尸进程(第二次遇到)
现象:nodemon 启动失败,提示端口被占。
netstat -ano | findstr :3000 看到一堆 TIME_WAIT 和 ESTABLISHED。
排查过程:
- 第一次以为是端口冲突,反复
taskkill杀进程 - 最后发现:文件名写错了,启动的根本不是当前文件
教训:
杀端口之前,先确认
nodemon启动的文件名对不对。
有时候不是端口被占,是你在错误目录或错误的文件名。
正确流程:
ls或dir确认当前目录有没有目标文件- 确认文件内容没错
- 再查端口、杀进程
四、“合并写法 vs 分开写法”
- 合并写法:
app.use(fn1, fn2, fn3)→ 代码紧凑,适合逻辑简单的中间件 - 分开写法:
app.use(fn1); app.use(fn2);→ 更易读、易调试
现在阶段用分开写法,因为更容易理解执行顺序,也方便加 console.log 调试。
五、6 个核心要点
| # | 要点 |
|---|---|
| 1 | 中间件 = 把一个大请求拆成多个小函数,每个做一件独立的事 |
| 2 | next() 是“放行”,不调用就会卡住;res.send() 是“结束”,只能调用一次 |
| 3 | use = 中间件(预处理、日志、解析),get/post = 路由(具体业务) |
| 4 | use 是前缀匹配(/user 匹配 /user/login),get/post 是精确匹配 |
| 5 | 中间件按顺序执行,next() 决定是否继续 |
| 6 | 合并写法与分开写法都行,你偏好分开(更清晰) |
六、今日小成就
- 自己画出了
use / method / all对比表 - 理解了中间件和路由的核心区别(管道 vs 水龙头)
- 解决了
next()+res.send()的冲突问题 - 第二次遇到端口冲突,最终发现是文件名写错
- 状态不好,但还是把内容学完了并总结出来了