静态文件服务 #
一、静态文件概述 #
1.1 什么是静态文件? #
静态文件是指不需要服务器动态处理的文件,如:
- CSS样式表
- JavaScript脚本
- 图片文件
- 字体文件
- HTML文件
1.2 express.static() #
Express内置的静态文件服务中间件:
javascript
app.use(express.static('public'));
二、基本用法 #
2.1 静态文件目录 #
创建public目录:
text
public/
├── css/
│ └── style.css
├── js/
│ └── main.js
├── images/
│ └── logo.png
└── index.html
2.2 配置静态文件服务 #
javascript
const express = require('express');
const app = express();
app.use(express.static('public'));
app.listen(3000);
访问:
http://localhost:3000/css/style.csshttp://localhost:3000/js/main.jshttp://localhost:3000/images/logo.pnghttp://localhost:3000/index.html
2.3 虚拟路径前缀 #
javascript
app.use('/static', express.static('public'));
访问:
http://localhost:3000/static/css/style.csshttp://localhost:3000/static/js/main.js
2.4 多个静态目录 #
javascript
app.use(express.static('public'));
app.use(express.static('uploads'));
app.use(express.static('files'));
Express按顺序查找文件,先找到的先返回。
三、配置选项 #
3.1 完整配置 #
javascript
app.use('/static', express.static('public', {
dotfiles: 'ignore',
etag: true,
extensions: ['htm', 'html'],
index: false,
lastModified: true,
maxAge: '1d',
redirect: true,
setHeaders: (res, path, stat) => {
res.set('x-timestamp', Date.now());
}
}));
3.2 配置选项说明 #
| 选项 | 说明 | 默认值 |
|---|---|---|
| dotfiles | 点文件处理 | ‘ignore’ |
| etag | 生成ETag | true |
| extensions | 默认扩展名 | false |
| index | 默认文件 | ‘index.html’ |
| lastModified | Last-Modified头 | true |
| maxAge | 缓存时间 | 0 |
| redirect | 目录重定向 | true |
| setHeaders | 自定义响应头 | - |
3.3 点文件处理 #
javascript
app.use(express.static('public', {
dotfiles: 'allow'
}));
| 值 | 说明 |
|---|---|
| ‘allow’ | 允许访问 |
| ‘deny’ | 拒绝访问 |
| ‘ignore’ | 忽略,当作不存在 |
3.4 默认扩展名 #
javascript
app.use(express.static('public', {
extensions: ['html', 'htm']
}));
访问 /about 会自动查找 about.html 或 about.htm。
3.5 禁用默认文件 #
javascript
app.use(express.static('public', {
index: false
}));
3.6 自定义默认文件 #
javascript
app.use(express.static('public', {
index: ['index.html', 'default.html']
}));
四、缓存控制 #
4.1 设置缓存时间 #
javascript
app.use('/static', express.static('public', {
maxAge: '1d'
}));
时间格式:
| 格式 | 说明 |
|---|---|
| ‘1d’ | 1天 |
| ‘1h’ | 1小时 |
| ‘1m’ | 1分钟 |
| ‘1s’ | 1秒 |
| 3600000 | 毫秒数 |
4.2 不同类型不同缓存 #
javascript
app.use('/css', express.static('public/css', {
maxAge: '7d'
}));
app.use('/js', express.static('public/js', {
maxAge: '1d'
}));
app.use('/images', express.static('public/images', {
maxAge: '30d'
}));
4.3 自定义缓存策略 #
javascript
app.use(express.static('public', {
setHeaders: (res, path) => {
if (path.endsWith('.html')) {
res.set('Cache-Control', 'no-cache');
} else if (path.match(/\.(css|js)$/)) {
res.set('Cache-Control', 'public, max-age=86400');
} else if (path.match(/\.(jpg|jpeg|png|gif|ico|svg)$/)) {
res.set('Cache-Control', 'public, max-age=2592000');
}
}
}));
五、安全考虑 #
5.1 限制访问目录 #
javascript
app.use('/static', express.static(path.join(__dirname, 'public')));
不要使用:
javascript
app.use(express.static('/'));
5.2 禁止目录列表 #
javascript
app.use(express.static('public', {
index: false
}));
5.3 自定义响应头 #
javascript
app.use(express.static('public', {
setHeaders: (res) => {
res.set('X-Content-Type-Options', 'nosniff');
}
}));
六、生产环境优化 #
6.1 使用反向代理 #
Nginx配置:
nginx
location /static/ {
alias /var/www/app/public/;
expires 30d;
add_header Cache-Control "public, immutable";
}
6.2 使用CDN #
javascript
app.use((req, res, next) => {
res.locals.cdnUrl = process.env.CDN_URL || '';
next();
});
模板中:
html
<link rel="stylesheet" href="<%= cdnUrl %>/css/style.css">
6.3 文件指纹 #
javascript
const assets = {
'css/style.css': '/css/style.abc123.css',
'js/main.js': '/js/main.def456.js'
};
app.locals.asset = (path) => assets[path] || path;
模板中:
html
<link rel="stylesheet" href="<%= asset('css/style.css') %>">
七、完整示例 #
7.1 项目结构 #
text
my-app/
├── public/
│ ├── css/
│ │ └── style.css
│ ├── js/
│ │ └── main.js
│ ├── images/
│ │ └── logo.png
│ └── favicon.ico
├── uploads/
│ └── user-photos/
├── views/
│ └── index.ejs
└── app.js
7.2 应用配置 #
javascript
const express = require('express');
const path = require('path');
const app = express();
app.set('view engine', 'ejs');
app.use(express.static(path.join(__dirname, 'public'), {
maxAge: '1d',
etag: true,
lastModified: true,
setHeaders: (res, filePath) => {
const ext = path.extname(filePath);
if (['.jpg', '.jpeg', '.png', '.gif', '.ico', '.svg'].includes(ext)) {
res.set('Cache-Control', 'public, max-age=2592000');
} else if (['.css', '.js'].includes(ext)) {
res.set('Cache-Control', 'public, max-age=86400');
} else if (ext === '.html') {
res.set('Cache-Control', 'no-cache');
}
res.set('X-Content-Type-Options', 'nosniff');
}
}));
app.use('/uploads', express.static(path.join(__dirname, 'uploads'), {
maxAge: '7d'
}));
app.get('/', (req, res) => {
res.render('index', { title: '首页' });
});
app.listen(3000, () => {
console.log('服务器运行在 http://localhost:3000');
});
7.3 模板文件 #
views/index.ejs:
html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title><%= title %></title>
<link rel="stylesheet" href="/css/style.css">
<link rel="icon" href="/favicon.ico">
</head>
<body>
<header>
<img src="/images/logo.png" alt="Logo">
<h1><%= title %></h1>
</header>
<main>
<p>欢迎来到Express静态文件示例</p>
</main>
<script src="/js/main.js"></script>
</body>
</html>
八、总结 #
静态文件服务要点:
| 配置 | 说明 |
|---|---|
| express.static(‘public’) | 基本配置 |
| express.static(‘public’, options) | 带选项配置 |
| ‘/static’ | 虚拟路径前缀 |
| maxAge | 缓存时间 |
| setHeaders | 自定义响应头 |
下一步,让我们学习数据库集成!
最后更新:2026-03-28