4.7 KiB
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 |
|
|
basic |
|
2.5 |
|
|
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 适合什么场景,不适合什么场景?