Node.js 中间层我维护了两年,这周终于摊牌了——成本账单算完我人傻了
背景先交代一下我在一个 20 人的创业团队做全栈两年前入职第一件事就是搭 Node.js 中间层。当时的理由很充分scss前端React SPA中间层Node.js (Express) ← 我搭的后端Java 微服务 × 6老板说前端不能直接调 Java原因有三接口格式不统一——有的返回 {code, data}有的返回 {status, result}跨域问题——6 个微服务 6 个域名前端需要做接口聚合——一个页面要调 3-4 个接口拼数据听起来确实需要一个 BFF 对吧我当时也这么想的。两年后的真实状态来看看我的 BFF 层现在长什么样bashsrc/├── routes/ # 87 个路由文件├── controllers/ # 87 个 controller一一对应├── services/ # 92 个 service├── middleware/ # 15 个中间件├── utils/ # 各种 helper└── config/ # 3 套环境配置87 个路由。你没看错。其中有多少是有意义的聚合逻辑我数了一下12 个。剩下的 75 个在干嘛javascript// 真实代码脱敏过占 BFF 总代码量的 85%router.get(/api/users/:id, async (req, res) {try {const result await javaService.get(/user-service/users/${req.params.id});res.json({ code: 0, data: result.data });} catch (err) {res.json({ code: -1, message: err.message });}});透传。纯透传。85% 的代码就是把前端的请求原封不动转发给 Java再把 Java 的响应原封不动还给前端。连参数校验都没做Java 那边做了。我维护了两年的中间层本质上是个超大号的 nginx proxy_pass。算一笔账这才是让我下定决心的原因。服务器成本BFF 层跑了 3 台 2C4G 的云服务器高可用嘛每台 ¥280/月iniBFF 服务器: ¥280 × 3 ¥840/月PM2 进程管理: 包含在内Nginx SSL: 包含在内监控告警Datadog: ¥200/月──────────────────────合计: ≈¥1,040/月人力成本这个才是大头markdown我每周花在 BFF 上的时间: ≈10 小时- 后端新增接口 → 我同步加 BFF 路由: 4h- Bug 修复 维护: 3h- 升级依赖 / 安全补丁: 2h- 写测试虽然覆盖率一直上不去: 1h按我的时薪折算: ≈¥1,500/周 ¥6,000/月一个月 ¥7,000维护一个高级转发器。而且这还不算隐性成本——每次后端改了接口我得同步改 BFF。经常出现「后端改了字段名忘了告诉我前端页面挂了半天才发现」的情况。这周动手了热榜那篇文章让我下定了决心。我列了个清单1. 75 个纯透传路由 → Nginx 反向代理直接搞定nginx# 原来 87 个 Node.js 路由文件 → 现在 15 行 nginx 配置location /api/user-service/ {proxy_pass http://java-user-service:8080/;proxy_set_header X-Real-IP $remote_addr;}location /api/order-service/ {proxy_pass http://java-order-service:8081/;proxy_set_header X-Real-IP $remote_addr;}# ...6 个微服务全部直连是的就这么简单。CORSNginx 加几行 header。认证Java 那边本来就有鉴权中间件。砍掉 BFF 的第一刀省了 85% 的代码量。2. 12 个聚合接口 → 前端用 Promise.all 自己聚合typescript// 以前BFF 聚合三个接口// GET /api/dashboard → 内部调 user order statistics// 现在前端直接并发请求const [user, orders, stats] await Promise.all([fetch(/api/user-service/me),fetch(/api/order-service/recent),fetch(/api/stat-service/dashboard),]);有人会说这不就是把复杂度推给前端了吗对但前端框架现在处理这个太轻松了。React Query / SWR 几行代码还自带缓存和错误重试。比我手写的 BFF 聚合逻辑健壮得多。3. 接口格式不统一写个前端拦截器typescript// axios 拦截器统一格式10 行代码解决api.interceptors.response.use((response) {const data response.data;// Java 服务 A: {code, data}// Java 服务 B: {status, result}return {success: (data.code 0 || data.status ok),data: data.data || data.result,message: data.message || data.error,};});以前用 BFF 做的格式统一一个拦截器就搞定了。重构结果花了两天时间结果makefile代码变化:删除: 87 个路由文件 92 个 service 所有 BFF 代码新增: 15 行 Nginx 配置 1 个前端拦截器 3 个 Promise.all 聚合服务器变化:关掉: 3 台 BFF 云服务器省钱: ¥1,040/月人力变化:我每周在 BFF 上的时间: 10h → 0h后端改接口不用通知我了: priceless 部署流程:之前: 前端 BFF 后端 3 个部署流水线现在: 前端 后端 2 个部署流水线但是不是所有中间层都该删说几个真正需要 Node.js 中间层的场景1. SSR / SSG— Next.js、Nuxt 这类框架本身就是 Node.js 中间层这个有真实价值2. 复杂的 BFF 编排— 如果你的聚合逻辑涉及条件分支、错误回退、事务补偿前端处理确实吃力3. AI API 代理— 这个是我新发现的场景说来有点讽刺我删掉 BFF 之后一个月团队开始往产品里加 AI 功能。结果发现又需要一个中间层了javascript// 又特么需要代理了 // 前端不能直接调 AI API密钥暴露 CORSrouter.post(/api/ai/chat, async (req, res) {const result await openai.chat.completions.create({model: gpt-4o,messages: req.body.messages,});res.json(result);});不过这次我学聪明了——没有自己搭 Node 服务而是用了 API 聚合平台做代理。类似 ofox.ai 这种统一一个 endpoint 调不同的模型前端只需要配一个 base_url 就行连 Node 中间层都省了。typescript// 前端直接调API Key 通过后端环境变量注入到 SSR 页面const client new OpenAI({apiKey: process.env.NEXT_PUBLIC_AI_KEY,baseURL: https://api.ofox.ai/v1,dangerouslyAllowBrowser: true, // 仅限内部工具});当然如果是面向用户的产品密钥肯定还是得走后端。但对内部工具来说这种方案省了一整个服务。给还在纠结的人几个建议先审计你的中间层代码——数一下有多少路由是纯透传的。如果超过 60%认真考虑砍掉。别因为万一以后需要而保留——YAGNI 原则。我在 BFF 层留了两年的预留扩展点一个都没用上。分步来——不用一口气全砍。我是先灰度切了 10 个低风险接口观察一周没问题再切剩下的。计算真实成本——不只是服务器费用。你的时间才是最贵的。每周花在同步 BFF 路由上的时间完全可以用来做更有价值的事。考虑团队现状——如果你的后端接口真的很乱、没有统一规范BFF 层可能还是必要的过渡方案。但目标应该是推动后端统一而不是用 BFF 永远兜底。最后Node.js 中间层不是原罪。无脑加中间层才是。两年前我搭 BFF 的时候确实解决了实际问题但随着项目发展它的维护成本已经远超收益。热榜说的从前端救星到成本噩梦我的体会是它确实当过救星但别让它变成你的舒适区。该摊牌的时候就摊牌吧 ✌️全栈开发一枚最近在折腾去中间层化。下一篇可能会写 Nginx 反向代理的完整配置方案感兴趣的朋友关注一波 原文链接https://juejin.cn/post/7611861210603257862
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2526677.html
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!