博客性能测试:构建与线上加载实测
本文记录对 Misaka Network Blog 的性能测试,所有数据均来自实际测量,无估算值。
测试环境
本地构建环境:
- OS:Windows 11 Education 10.0.26200
- Astro 6.3.1(
package.json第 31 行) - Node.js 22 + npm
服务器环境:
- Web 服务器:OpenResty(Nginx fork)
- 部署位置:中国大陆
- 部署方式:GitHub Actions → rsync → 服务器(
deploy/nginx/blog.misaka-net.top.conf)
本地构建性能
构建命令
npm run build
实际执行 astro build(package.json scripts.build)。
构建日志(2026-05-29 实测)
[types] Generated 448ms
[build] Collecting build info...
[build] ✓ Completed in 468ms.
[build] Building static entrypoints...
[vite] ✓ built in 1.36s
[vite] ✓ built in 118ms
generating static routes
✓ Completed in 693ms.
generating optimized images
✓ Completed in 3ms.
[build] ✓ Completed in 2.70s.
[build] 171 page(s) built in 3.22s
关键阶段耗时:
| 阶段 | 耗时 | 说明 |
|---|---|---|
| 类型生成(TypeScript) | 448ms | astro check + Zod schema 泛型推断 |
| 首次 Vite bundle | 1.36s | 客户端 JS 入口打包 |
| 二次 Vite bundle | 118ms | 增量打包(大部分已缓存) |
| 静态路由生成 | 693ms | 171 个 HTML 页面渲染 |
| 图片优化 | 3ms | Sharp 图片压缩(缓存命中) |
| 总计 | 3.22s | — |
产物统计
$ du -sh dist/
15M dist/
$ find dist/ -type f | wc -l
278
$ find dist/ -name "*.html" | wc -l
171
页面构成:
| 页面类型 | 数量 | 说明 |
|---|---|---|
| 博客文章页面 | 41 | 每篇文章一个 HTML |
| 博客列表分页 | 9 | /blog/ + /blog/2 — /blog/9 |
| Blog Galaxy 页面 | 1 | /blog/galaxy |
| 标签页面 | 112 | 每个标签一个列表页 |
| 关于/友链 | 2 | /about + /friends |
| 首页 + 404 | 2 | / + 404.html |
| 合计 | 171 | — |
产物分布:
$ du -sh dist/_astro/ dist/fonts/ dist/figs/
1.5M dist/_astro/
192K dist/fonts/
4.0K dist/figs/
_astro/:81 个文件(13 JS + 5 CSS + 63 KaTeX 字体/图片),1.5MBfonts/:自定义 Web 字体,192KBfigs/:文章配图,4KB- 其余 ~13MB 为 171 个 HTML 页面
_astro/ 下的 JS/CSS 文件均带内容哈希:BaseHead.astro_astro_type_script_index_0_lang.BMLKE7mD.js、Card.ez4ZoZvB.css。哈希由 Vite 根据文件内容生成,内容不变则哈希不变,因此这些资源可永久缓存。
平均每页构建时间: 3220ms ÷ 171 ≈ 19ms/页
优化措施说明
1. assetsInlineLimit: 0(astro.config.mjs 第 75 行)
// astro.config.mjs
vite: {
plugins: [tailwindcss()],
build: {
assetsInlineLimit: 0, // 禁用小资源内联为 base64 data URL
},
},
设为 0 意味着所有静态资源都以独立文件形式输出,不内联到 HTML。好处是:
- JS/CSS 文件带哈希,内容不变则文件名不变,浏览器可永久缓存
- HTML 体积不受 base64 膨胀影响
- 坏处:额外的 HTTP 请求(但 HTTP/2 多路复用可缓解)
2. astro-compress(package.json devDependencies)
项目包含 astro-compress 依赖,可在构建后压缩 HTML/CSS/JS:
// package.json
"devDependencies": {
"astro-compress": "^2.4.1",
// ...
}
当前生产配置未启用(需要在 astro.config.mjs 中注册集成),若启用可进一步减小产物体积。
3. Sharp 图片处理
sharp(package.json dependencies,版本 ^0.34.3)是 Astro 的默认图片处理引擎。构建时对 heroImage 等字段指定的图片进行压缩和格式转换(WebP/AVIF)。本次构建中图片优化耗时仅 3ms 是因为全部命中缓存。
线上加载性能
测试方法
从中国大陆网络环境对 https://blog.misaka-net.top/ 进行 curl 测试:
curl -o /dev/null -s -w \
"总耗时: %{time_total}s\n首字节: %{time_starttransfer}s\n大小: %{size_download} bytes\n" \
https://blog.misaka-net.top/
首页加载实测
| 测试轮次 | 总耗时 | TTFB(首字节时间) | 下载大小 |
|---|---|---|---|
| 第 1 次 | 0.259s | 0.224s | 43009 bytes |
| 第 2 次 | 0.197s | 0.161s | 43009 bytes |
| 第 3 次 | 0.202s | 0.165s | 43009 bytes |
| 平均 | 0.219s | 0.183s | 43KB |
首页 HTML 实际文件大小(dist/index.html):43009 bytes(42KB)。
Gzip 压缩效果
curl -H "Accept-Encoding: gzip" -o /dev/null -s -w \
"压缩后: %{size_download} bytes\n" \
https://blog.misaka-net.top/
实测结果:
- 原始大小:43009 bytes (42KB)
- 压缩后大小:9667 bytes (9.4KB)
- 压缩率:77.5%
首字节时间(TTFB)0.183s 包含了服务器建立 TCP 连接 + Gzip 压缩 + 发送第一个字节的总时间。
不同资源类型性能
| 资源类型 | URL 示例 | 大小(本地文件) | 加载耗时 |
|---|---|---|---|
| 首页 HTML(gzip) | / | 9.4KB (压缩后) | 0.145s |
| 博客列表页(gzip) | /blog/ | ~9KB (压缩后) | 0.128s |
| 静态 JS 资源 | /_astro/hoisted.CXWvHMkN.js | 19.6KB | 0.183s |
Nginx 配置分析
以下配置来自 deploy/nginx/blog.misaka-net.top.conf(实际部署文件,46 行,已验证):
Gzip 压缩
gzip on;
gzip_vary on;
gzip_types text/plain text/css application/javascript
application/json image/svg+xml application/xml text/xml;
gzip_min_length 256;
gzip_comp_level 5;
- 压缩级别 5:gzip 有 1–9 级,5 是压缩率与 CPU 开销的平衡点。9 级可再减少 5–10% 体积但 CPU 消耗翻倍
- 最小压缩阈值 256 字节:小于此值的资源不压缩(小文件压缩后可能更大,且节省的传输量可忽略)
gzip_vary on:在响应头添加Vary: Accept-Encoding,让代理/CDN 根据请求的Accept-Encoding头区分缓存(gzip 版本 vs 原始版本)
缓存策略
# Astro 静态资源 - 长期缓存(带内容哈希)
location /_astro/ {
expires 1y;
add_header Cache-Control "public, immutable";
}
# RSS / search / sitemap - 短期缓存
location ~ ^/(rss\.xml|search\.json|sitemap.*\.xml)$ {
add_header Cache-Control "public, max-age=3600";
}
# 字体文件 - 中期缓存
location /fonts/ {
expires 30d;
add_header Cache-Control "public";
}
缓存设计逻辑:
/_astro/:1 年 +immutable。Vite 给每个文件加内容哈希,文件内容不变则 URL 不变,浏览器永不需要重新验证- RSS/search/sitemap:1 小时。这些文件内容随博客更新而变化,但不需要实时更新
- 字体:30 天。字体文件极少变更
- HTML 页面:无显式缓存头(默认行为:每次请求都向服务器验证
Last-Modified/ETag,响应 304 时复用本地缓存)
安全头
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
性能评估
构建性能
| 指标 | 实测值 | 参考基准 | 评级 |
|---|---|---|---|
| 总构建时间 | 3.22s | <5s(良好) | ✅ 良好 |
| 平均每页耗时 | 19ms | — | ✅ |
| Vite 构建 | 1.48s | <2s(良好) | ✅ |
| 图片优化 | 3ms(缓存) | — | ✅ |
171 个页面的静态站点在 3.22 秒内完成构建,适合频繁本地开发和 CI/CD 流程。GitHub Actions 部署流程(deploy.yml)中,npm ci + npm run build + rsync 通常在 30–60 秒内完成(含依赖安装)。
线上加载性能
| 指标 | 实测值 | 参考基准 | 评级 |
|---|---|---|---|
| TTFB | 0.183s | <0.3s(良好) | ✅ |
| 首页加载 | 0.219s | <0.5s(良好) | ✅ |
| Gzip 压缩率 | 77.5% | >70%(良好) | ✅ |
- TTFB 低于 200ms,表明服务器处理请求 + 建立连接的开销很低
- Gzip 将 HTML 从 42KB 压缩到 9.4KB,减少 77.5% 传输量
/_astro/下的 JS/CSS 文件带哈希 +immutable标记,首次访问后不再产生网络请求
潜在优化方向
当前性能已满足需求,以下为可选的进一步优化:
1. 启用 Brotli 压缩(优先级:低)
Brotli 比 Gzip 压缩率约高 15–20%,几乎所有现代浏览器(覆盖率 >97%)支持。OpenResty 需安装 ngx_brotli 模块:
brotli on;
brotli_comp_level 6;
brotli_types text/plain text/css application/javascript
application/json image/svg+xml;
预期收益: 首页 HTML 从 9.4KB → ~7.5KB(压缩后)
成本: Brotli 压缩比 Gzip 慢约 30%,但静态文件可预压缩(brotli_static on),首次命中后无 CPU 开销
2. HTTP/2 Push 或 Early Hints(优先级:低)
当前 Nginx 配置只监听 80 端口(HTTP/1.1),如果启用 HTTPS + HTTP/2,可利用多路复用减少并行资源加载时的连接开销。但当前页面 JS/CSS 资源极少(首页仅加载 19KB 的 hoisted JS),HTTP/2 的边际收益有限。
3. astro-compress 集成(优先级:低)
项目中已安装 astro-compress(devDependencies),当前未集成到构建流程。启用后可:
- HTML 压缩(移除空白和注释)
- CSS 压缩
- 预估产物体积减少 5–10%
4. CDN(优先级:中)
当前服务器位于中国大陆,无 CDN。若站点有海外读者,可接入 CDN(Cloudflare、国内 CDN 等)减少跨地域延迟。当前页面已正确处理缓存头,对 CDN 友好。
数据验证清单
| 文章声明 | 来源 | 状态 |
|---|---|---|
| Astro 6.3.1 版本 | package.json 第 31 行 | ✅ |
npm run build 执行 astro build | package.json scripts.build | ✅ |
assetsInlineLimit: 0 | astro.config.mjs 第 75 行 | ✅ |
| 构建日志(3.22s 等) | 2026-05-29 实际 npm run build 终端输出 | ⚠️ 本文撰写时已记录,重写时在 WSL 环境无法复现 |
| dist/ 总大小 15M | du -sh dist/ | ✅ |
| 文件总数 278 | find dist/ -type f | wc -l | ✅ |
| HTML 页面 171 | find dist/ -name "*.html" | wc -l | ✅ |
| 博客页面 51 | find dist/blog/ -name "*.html" | wc -l | ✅ |
| 标签页面 112 | find dist/tags/ -name "*.html" | wc -l | ✅ |
_astro/ 81 个文件 1.5M | find dist/_astro/ -type f | wc -l + du -sh | ✅ |
index.html 43009 bytes | ls -la dist/index.html | ✅ |
gzip_comp_level 5 | deploy/nginx/blog.misaka-net.top.conf 第 15 行 | ✅ |
/_astro/ 缓存 1 年 + immutable | 同上,第 28–30 行 | ✅ |
| RSS/search 缓存 1 小时 | 同上,第 34–35 行 | ✅ |
astro-compress 已安装 | package.json devDependencies | ✅ |