Day13:中间件--把一个大请求拆成多个小函数(核心思想)

7 阅读3分钟

今天状态不好,零零散散学了一天,但最后自己手画了一张对比表,把 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 启动的文件名对不对。
有时候不是端口被占,是你在错误目录或错误的文件名。

正确流程

  1. ls 或 dir 确认当前目录有没有目标文件
  2. 确认文件内容没错
  3. 再查端口、杀进程

四、“合并写法 vs 分开写法”

  • 合并写法app.use(fn1, fn2, fn3) → 代码紧凑,适合逻辑简单的中间件
  • 分开写法app.use(fn1); app.use(fn2); → 更易读、易调试

现在阶段用分开写法,因为更容易理解执行顺序,也方便加 console.log 调试。


五、6 个核心要点

#要点
1中间件 = 把一个大请求拆成多个小函数,每个做一件独立的事
2next() 是“放行”,不调用就会卡住;res.send() 是“结束”,只能调用一次
3use = 中间件(预处理、日志、解析),get/post = 路由(具体业务)
4use 是前缀匹配/user 匹配 /user/login),get/post 是精确匹配
5中间件按顺序执行,next() 决定是否继续
6合并写法与分开写法都行,你偏好分开(更清晰)

六、今日小成就

  • 自己画出了 use / method / all 对比表
  • 理解了中间件和路由的核心区别(管道 vs 水龙头)
  • 解决了 next() + res.send() 的冲突问题
  • 第二次遇到端口冲突,最终发现是文件名写错
  • 状态不好,但还是把内容学完了并总结出来了