Files
zhuangang/topics/backend/nodejs/01-express-nest-basics.md
T

4.7 KiB
Raw Blame History

id, title, type, domain, stack, tags, level, prerequisites, est_hours, related, week, order
id title type domain stack tags level prerequisites est_hours related week order
backend.nodejs.express-nest Node.js 后端(了解级):事件循环、Express 5 中间件与错误处理、NestJS 的模块化思路、做 BFF lesson backend
nodejs
Node.js
事件循环
Express 5
中间件
错误处理
NestJS
依赖注入
BFF
SSE
basic
frontend.typescript.type-system
2.5
frontend.ssr.nextjs-app-router
backend.nodejs.scenario.ai-bff
backend.nodejs.interview
7
14
1

Node.js 后端(了解级):事件循环、Express 5 中间件与错误处理、NestJS 的模块化思路、做 BFF

定位:了解并能写。你的主线后端是 Go(基础)+ Python(AI / Agent)。BOSS直聘 2026-10-23 的调研中有岗位提到 Node.js / Next.js,前端出身的候选人被问到 Node 的概率很高。示例基于 Node 24 + Express 5 实际运行通过;NestJS 部分是示意代码,未编译。以官方文档为准:https://nodejs.org/docs 、https://expressjs.com/ 、https://docs.nestjs.com/ 。

解释说明

事件循环(面试必问)

Node 单线程执行 JS,I/O 交给系统异步完成,回调放进队列。事件循环的主要阶段:timers(setTimeout)→ pending callbacks → poll(I/O)→ check(setImmediate)→ close callbacks;每个阶段之间先清空 process.nextTick 队列和 Promise 微任务队列。

结论:适合 I/O 密集(BFF、网关、实时推送);CPU 密集的计算会阻塞所有请求,要放到 worker_threads 或其他服务。

Express 5

  • 中间件:(req, res, next) 按注册顺序执行,类似 Gin 的中间件链。
  • 错误处理中间件:4 个参数 (err, req, res, next),放在最后。
  • Express 5 的变化:async 处理函数抛出的错误 / 被拒绝的 Promise 会自动传给错误处理中间件(Express 4 需要手动 next(err));路由路径语法也有调整(以迁移指南为准)。

NestJS

在 Express(或 Fastify)之上提供 Angular 风格的结构:模块(Module)、控制器(Controller)、服务(Provider)、依赖注入、管道(Pipe,做校验)、守卫(Guard,做鉴权)、拦截器(Interceptor)。适合中大型团队统一规范。对照:Go 中你手写依赖注入,FastAPI 用 Depends。

为什么前端团队常用 Node 做 BFF

同一语言、类型可以共享;聚合多个后端接口、裁剪字段;统一鉴权、限流;流式转发 AI 回答。

案例

AI 客服的 BFF:校验登录、限流、为每个请求生成 request id,调用 Python AI 服务并把流式回答以 SSE 转发给浏览器;客户端断开时中止上游。

代码示例

examples/express-bff:node --test app.test.ts 4 个测试通过、tsc 通过,node server.ts 启动后 curl -N 观察到每 200ms 到达一条 SSE 事件。

// Express 5:async 路由中直接 throw,由统一错误处理中间件返回
app.get("/orders/:id", async (req, res) => {
  if (!/^[A-Z]\d{3,}$/.test(req.params.id)) throw new HttpError(400, "BAD_ORDER_ID", "订单号格式不正确");
  const order = await deps.findOrder(req.params.id);
  if (!order) throw new HttpError(404, "ORDER_NOT_FOUND", "订单不存在");
  res.json(order);
});

app.use((err: unknown, _req: Request, res: Response, _next: NextFunction) => {
  if (err instanceof HttpError) { res.status(err.status).json({ code: err.code, message: err.message }); return; }
  res.status(500).json({ code: "INTERNAL", message: "服务器内部错误" });   // 不暴露内部细节
});

NestJS 的写法(示意,未编译;需要装饰器相关的编译配置):

@Controller("orders")
export class OrdersController {
  constructor(private readonly orders: OrdersService) {}          // 依赖注入

  @Get(":id")
  @UseGuards(AuthGuard)                                             // 鉴权
  find(@Param("id") id: string) {
    return this.orders.findOne(id);                                 // 抛出 NotFoundException 自动转成 404
  }
}

易错点

  • 在请求处理中做大量同步计算(大 JSON 序列化、加密、图片处理),阻塞所有请求。
  • Express 4 的项目里 async 错误没有 next(err),请求挂起直到超时。
  • SSE 响应头发出后出错,还试图设置状态码。
  • 没有监听客户端断开,上游 AI 继续生成、浪费 token。
  • 未处理的 Promise 拒绝导致进程退出:要有全局监控和进程守护。

面试常问

  • 讲讲 Node 的事件循环,process.nextTick、Promise、setTimeout、setImmediate 的顺序?
  • Express 中间件原理?错误处理怎么做?
  • Node 适合什么场景,不适合什么场景?