被低估也被骂惨的Express:跑在一半互联网后端上的"新手框架"

上周帮一个刚创业的朋友排查后端接口超时的问题,翻了三层代码层才发现,他用的Express 4.x版本,连最基础的路由缓存都没开。

他还挺委屈,说自己跟着网上的教程写的,教程里根本没提这回事。

说起来也正常,很多人对Express的认知还停留在大学计算机网络实验课上,跟着教程写个三行代码就能跑起一个返回”Hello World”的接口,觉得这就是个给新手练手的玩具,根本配不上生产环境的要求。

你以为Express只是个“入门级框架”?

别被它的低门槛骗了。全球Top1000万网站里有近30%的后端服务跑在Node.js生态上,而第三方扫描机构的统计数据显示,这部分服务里超过6成的Web层底层用的都是Express。

你每天刷的社交媒体的用户接口、用的企业SaaS的审批后台、甚至很多大厂内部的运维工具、测试平台,可能都跑在这个你瞧不上的“新手框架”上。

它能在竞争激烈的Node.js生态里活了14年,靠的从来不是什么高性能或者企业级的强约束,就是一个字:薄。

薄到什么程度?它把Node.js原生的http模块包了一层,没有强制的目录结构,没有强制的数据库选型,没有强制的鉴权方案,你想怎么写就怎么写。想加个跨域处理,挂个中间件就行;想加个路由,写个app.get()就行;哪怕你想把整个业务逻辑直接塞到路由回调里,它也不会拦着你。

这种完全开放的设计,让它成了所有Node.js工具链的“默认适配对象”。你现在去npm上搜任何和后端相关的包,从JWT鉴权到文件上传,从日志采集到参数校验,几乎第一个给出的接入示例就是Express版本的。你要是用别的框架,比如NestJS、Fastify,还得自己把示例代码改半天,适配各自的插件或者装饰器体系。

哦对,它的核心执行逻辑就是大家常说的洋葱模型。请求进来,一层层穿过所有注册的中间件,到路由处理逻辑,再一层层原路返回响应。

Express.js 中间件洋葱模型执行流程图
Express.js 中间件洋葱模型执行流程图

被“过度简单”绑架的技术边界

说实话,Express的设计哲学从一开始就走了个极端。

它把所有的控制权都给了你,但也把所有的坑都留给了你。

没有约束就意味着没有兜底。我见过太多刚学后端的人写的Express代码:没有全局错误处理中间件,接口抛个未捕获的异常直接把整个Node进程打挂;没有请求体大小限制,被人刷个几兆的恶意payload就直接内存溢出;没有接口超时配置,上游服务卡个几十秒,整个服务的线程池直接被占满。

之前某电商大促的时候就出过一次事,一个内部用的库存查询服务跑在Express上,因为没做请求频率限制,被内部的自动化测试脚本不小心刷了几万次请求,直接把整个服务打挂,导致前端的库存显示全是空值,损失了快小几百万的销售额。事后排查的时候,负责这个服务的工程师挠着头说,他当初写这个服务的时候,就是跟着教程搭的Express,根本不知道还要加频率限制的中间件。

当然这也不能全怪开发者。Express本身的定位就是一个“无感知的Web层封装”,它不会主动告诉你你缺了什么配置,也不会在你写了有问题的代码的时候给你报错,一切全靠开发者自己的经验。

不过话说回来,这种过度简单的设计,也让Express的技术边界变得异常清晰:它永远不会去做那些“超出Web层封装”的事。你要ORM?自己配;你要依赖注入?自己写;你要单元测试的集成支持?自己搞。它就守着自己那点路由处理、中间件调度的核心功能,别的一概不管。

站在换代十字路口的Express生态

Express 4.x的大版本从2015年用到现在,整整10年了。

我之前帮一个跑了6年的老项目升级的时候,光给100多个异步路由补错误捕获的wrapper,就花了整整两天。那两天我对着代码骂Express的祖宗十八代都有了——到现在它都不能原生支持async函数中间件的错误捕获,你写个async的中间件,里面抛个错,它直接给你吞掉,连个日志都不打。

核心维护团队的规模小得可怜。当年的作者TJ Holowaychuk早就把项目捐给了开源基金会,现在真正能合并代码的核心维护者也就3个人,大部分的代码提交都是社区志愿者贡献的。更新速度慢到什么程度?大家盼了好几年的Express 5.0,从2016年开始发alpha版本,到现在都还没出正式版。

现在的Node.js生态早就不是Express一家独大了。

2024年Node.js主流后端框架吞吐量性能对比图
2024年Node.js主流后端框架吞吐量性能对比图

性能端有Fastify,吞吐量是Express的3-4倍,原生支持async函数的错误捕获,自带schema参数校验,插件体系也成熟,现在很多新的中小型项目都开始选Fastify了。企业级端有NestJS,用类似Angular的强约束架构,强制分层,依赖注入,大团队协作的时候根本不会写出那种一个函数1000行的屎山,现在很多中大型公司的新项目,只要是超过5个人的团队,基本都选NestJS。

但Express的基本盘还是稳得离谱。

你现在去Github上搜公开的Node.js后端项目,超过一半的老项目都是Express写的。很多公司根本不敢动这些老项目——迁移成本太高了。一个跑了五六年的Express系统,上面挂着几百个路由,几十个定制化的中间件,你要全量迁到Fastify或者NestJS,没有个半年一年根本下不来。万一迁移过程中出个线上故障,比如支付接口报错,用户信息漏传,那损失可比你省下来的那点性能钱多得多。

被忽视的基础设施风险

被忽视的基础设施风险
被忽视的基础设施风险

很多人根本没意识到,Express现在已经成了整个互联网生态里最“脆弱”的基础设施之一。

核心维护团队人少,没有稳定的企业赞助,很多安全漏洞都是靠社区的安全研究者主动报的。之前出过好几次严重的漏洞:比如路由匹配的正则表达式DoS漏洞,攻击者构造个特殊的请求路径,就能把服务的CPU直接占满;还有参数污染的漏洞,攻击者在请求里传个重复的参数,就能绕过之前的权限校验。这些漏洞的补丁往往要隔好几个月才能正式发布,很多小公司根本不会主动去跟踪这些漏洞的更新,相当于直接把自己的服务暴露在风险里。

还有个更隐蔽的问题,就是Express代码的可维护性。因为没有强制的规范,很多Express项目的代码都是随着业务迭代堆起来的,今天加个路由,明天加个中间件,根本没有统一的架构设计。我见过最离谱的一个项目,把所有的业务逻辑都写在一个1500行的路由回调函数里,连个注释都没有。上次那个写代码的作者离职之后,接手的人根本不敢改,一改就出bug,最后只能在外面套个新的服务,把老接口慢慢代理迁移出去,光这个过程就花了快一年。

未来3-5年的几个确定判断

首先,Express不会死。

它已经成了Node.js生态的“通用底座”。现在的NestJS默认的底层适配器就是Express,很多新的框架为了抢习惯了Express的开发者,都会兼容Express的中间件写法。哪怕你以后用的是新的框架,可能底层还是在间接跑着Express的代码。它不会再是新项目的首选直接选型,但会一直作为兼容层存在,就像现在很多网站还在跑的PHP 7一样。

其次,存量的Express项目会慢慢进入“半维护”状态。

大家不会再给这些项目加新的大功能,只会修bug,补安全补丁,能跑就不动。毕竟迁移的成本太高,谁也不愿意为了一个已经稳定跑了好几年的系统,冒线上故障的风险。

最后,Express的设计思路会被慢慢拆解吸收。

现在的Fastify已经支持类似Express的极简路由写法,就是为了降低老Express开发者的迁移成本。未来的Node.js后端框架,会把Express的薄封装、低门槛的优势,和其他框架的强约束、高性能的特点结合起来,不会再有哪个框架像Express一样,为了灵活把所有的坑都留给开发者。

上次那个创业的朋友,最后还是把路由缓存开了,接口超时的问题一下就解决了。他说早知道Express这么多坑,当初还不如直接选Fastify。

但没办法,谁让他当初跟着教程学的第一个后端框架,就是Express呢。

作者|大讲堂

排版|大讲堂

审核|白杨

免责声明:市场有风险,选择需谨慎!此文仅供参考,不作买卖依据。如有侵权请联系删除。
文章名称:被低估也被骂惨的Express:跑在一半互联网后端上的"新手框架"
文章链接:https://lfdjt.com/info_23_25683.html