当前位置: 首页> 技术教程> 正文

Express静态文件教程

宁旺春土特产品

在使用Express搭建后端服务或全栈项目的过程中,静态文件托管是几乎每个项目都会用到的基础能力,不管是纯HTML页面、CSS样式表、前端JavaScript文件,还是图片、字体、PDF这类资源,都需要通过静态文件服务让客户端能够直接访问,不少刚接触Express的开发者会在路径配置、资源404、SPA路由兼容等问题上踩坑。其实Express从4.x版本开始就内置了专门的静态文件托管中间件`express.static`,无需额外安装第三方包,只需简单配置就能满足绝大多数场景的需求,只要理清它的运行逻辑和配置细节,就能轻松应对各类静态资源托管需求。

Express静态文件教程

很多初学者第一次接触静态文件托管时,往往会直接照搬教程里的`app.use(express.static('public'))`写法,在本地测试时一切正常,可一旦换个目录启动项目、或是部署到服务器上就会出现大面积404,核心原因就在于`express.static`的第一个参数如果传入相对路径,它的基准路径是启动Node.js进程的工作目录,而非当前JavaScript文件所在的目录。比如你的项目根目录是`my-project`,入口文件是`app.js`,静态资源放在`public`文件夹下,如果你在项目根目录执行`node app.js`,相对路径`public`会被解析为`my-project/public`,访问自然正常;可如果你在上一级目录执行`node my-project/app.js`,相对路径`public`就会被解析为与`my-project`同级的`public`文件夹,自然找不到资源。要彻底解决这个问题,最稳妥的方式是使用Node.js的`path`模块拼接绝对路径,结合`__dirname`变量(代表当前文件所在的目录)生成静态目录的绝对路径,写法为`const path = require('path'); app.use(express.static(path.join(__dirname, 'public')))`,这样无论从哪个目录启动进程,静态目录的路径都不会出错。

如果不想让静态资源直接挂载在服务的根路径下,我们还可以给静态文件服务添加虚拟路径前缀,只需要给`app.use`传入第一个参数作为路径前缀即可。比如`app.use('/static', express.static(path.join(__dirname, 'public')))`,此时原本访问`/css/style.css`的资源就需要通过`/static/css/style.css`来访问。这种写法的适用场景非常多:既可以清晰区分静态资源和接口路径,避免静态文件路径与业务路由产生冲突;也可以在同一个服务中托管多套静态资源,比如后台管理系统的前端文件挂在`/admin`前缀下,用户端的前端文件挂在`/`路径下,彼此互不干扰。

当项目中有多个静态资源目录时,我们可以多次调用`app.use(express.static(...))`来注册多个静态文件中间件,Express会按照注册顺序依次查找对应文件,找到第一个匹配的文件就返回。比如我们同时注册了`public`和`assets`两个静态目录,如果两个目录下都存在名为`logo.png`的文件,请求时会优先返回先注册的`public`目录下的文件。需要注意的是,如果所有静态目录中都找不到对应文件,Express会默认将请求传递给后续的中间件或路由处理,而非直接返回404,这个特性是由`express.static`的`fallthrough`配置项控制的,默认值为`true`,如果将其设为`false`,找不到文件时会直接返回404,不再向下传递。

除了基础的路径配置,`express.static`还支持通过第二个参数传入配置对象,调整静态服务的行为。其中最常用的是`maxAge`配置,用于设置静态资源的浏览器缓存时间,适合在生产环境中使用,比如`maxAge: '1d'`就代表浏览器会缓存静态资源一天,期间再次访问不会向服务器发起请求,能有效减少服务器压力和页面加载时间。还有`index`配置,默认值为`index.html`,表示当访问的路径是一个目录时,会自动查找该目录下的`index.html`文件返回,如果你不希望自动返回目录首页,可以将其设为`false`。另外还有用于自定义响应头的`setHeaders`配置,我们可以通过它给不同类型的文件设置不同的缓存策略,比如给带哈希值的前端打包文件设置一年的长缓存,给HTML文件设置不缓存,实现更精细化的性能优化。

现在前后端分离的单页应用(SPA)非常普遍,很多开发者会把React、Vue等框架打包后的文件放在Express中托管,这时候除了基础的静态文件配置,还需要解决客户端路由刷新404的问题。因为SPA的路由是在客户端处理的,服务端并没有对应路径的文件,直接刷新类似`/user/123`这样的路径时,会因为找不到文件而返回404。解决这个问题的方法是添加一个兜底路由,在所有静态资源中间件之后,注册一个匹配所有GET请求的路由,统一返回SPA的入口HTML文件,写法为`app.get('*', (req, res) => { res.sendFile(path.join(__dirname, 'dist', 'index.html')) })`。需要特别注意的是,这个兜底路由一定要放在静态文件中间件和业务接口路由之后,否则会拦截静态资源和接口的请求,导致所有请求都返回HTML文件。如果你的接口都有统一的前缀(比如`/api`),还可以把兜底路由的匹配规则调整为`app.get(/^(?!\/api).*/, ...)`,避免误拦截接口请求。

使用静态文件服务时还有一个容易被忽略的安全问题:绝对不要把包含敏感信息的目录设为静态目录,比如项目根目录、`node_modules`目录、存放配置文件的目录等,否则攻击者可能通过路径直接下载你的`.env`配置文件、后端源码等敏感数据,造成严重的安全隐患。默认情况下`express.static`会忽略以点开头的隐藏文件(由`dotfiles`配置项控制,默认值为`ignore`),但我们仍然建议只把专门存放公开静态资源的目录设为静态目录,从根源上避免安全风险。如果需要禁止访问某些特定类型的文件,也可以在静态中间件之前添加一个自定义中间件,对请求路径进行校验,匹配到敏感文件时直接返回403。

对于中小型项目或者开发环境来说,用Express托管静态文件已经完全足够,但在生产环境中,如果静态资源量很大、访问量很高,更建议用Nginx等反向代理服务器来托管静态资源,它们处理静态文件的性能远高于Node.js,还能更好地支持压缩、缓存、CDN联动等优化手段,Express则只需要负责处理业务接口即可,这样的架构会更加高效和稳定。

PC右下角
wap底部