我们把网站从HTML切到Nuxt 3,一天踩了5个坑(附检查清单)
SFD实验室真实案例:从HTML静态站迁移到Nuxt 3 SSR,一天踩了5个坑。Nginx图片404、Mock数据未清理、SSR源码异常、UI对比度问题、验收流程缺失——附完整架构迁移检查清单。


前言:一天搞定架构迁移,代价是什么?
3月21日,SFD实验室把官网从纯HTML静态站迁移到了Nuxt 3 SSR。
听起来很酷对吧?一天搞定架构升级,现代化框架、服务端渲染、SEO友好——简历上又多一行。
但实际情况是:老板打开首页,插画全部破图。点进文章,"文章不存在"。手机端汉堡菜单看不见。curl一下源码,满眼not-found。
一天之内,我们踩了5个坑,每个都是架构切换时最容易忽略的盲区。今天把这些坑全部摊开聊,省得你再走一遍。
坑1:Nginx切了proxy_pass,图片全炸了
💥 现象
切换上线后老板第一个打开首页,所有插画——全部破图。控制台一排排404,/uploads/和/images/下面的图片一个都加载不出来。
🔍 排查
旧站是纯HTML,Nginx直接serve那个目录,/uploads/logo.png这种路径天然就能访问到文件。但切了proxy_pass给Nuxt的Node进程之后,请求全部转发到了3000端口。Node进程里压根没有这些静态文件——它只管渲染Vue组件,哪知道你的图片在磁盘哪个角落?
🎯 根因
架构切换时只改了主路由的转发,完全忘了静态资源还在旧目录里。proxy_pass是个"全拦截"的操作,你没单独放行的路径,全都会被转发到Node。
🔧 修复
在Nginx配置里加了3个location block:
location /uploads/ {
alias /var/www/old-site/uploads/;
}
location /images/ {
alias /var/www/old-site/images/;
}
location /api/ {
proxy_pass http://127.0.0.1:8370;
}
就这么几行,但不写就全炸。
📝 教训
切proxy_pass之前,先把旧站所有的静态资源路径列出来。用grep或者find扫一遍HTML/CSS/JS里引用的路径,确保每一条在新架构下都有人"接住"。不要假设"Nuxt会自动处理"——它不会。
坑2:文章详情页全部"文章不存在"
💥 现象
首页看着挺好,文章列表也有数据。但只要点进任何一篇文章的详情页——"文章不存在"。所有文章,无一例外。
🔍 排查
翻前端代码一看,好家伙。变色龙同学写了一堆Mock假数据:mockSciencePosts、mockTechArticles……列表页用的是这些假数据,所以首页和列表看起来正常。但详情页需要根据slug去查具体文章,Mock数据里没有对应内容,直接返回空。
验收的时候呢?只看了首页和列表页。没人点进文章详情。
🎯 根因
两个问题叠加:一是开发用Mock数据做原型没问题,但上线前没替换成真实API调用;二是验收不够深,只看了"第一层"。
修的时候还踩了个额外的坑:lang参数不匹配。前端传的是"zh-CN",但CMS API只认"zh"。就这两个字符的差异,查了好一会儿。
🔧 修复
删掉了300多行Mock数据代码,全部替换成useAsyncData + $fetch直接调CMS的REST API。lang参数做了映射,"zh-CN"→"zh","en-US"→"en"。
📝 教训
上线前必须grep全项目"mock"关键词。这不是建议,是铁律。Mock数据就像脚手架,盖楼的时候需要,交房的时候必须拆干净。不然住进去的人(用户)看到的就是毛坯。
验收也一样:不能只看首页。必须点开至少3篇文章,看详情页能不能正常渲染。
坑3:SSR源码里藏着"not-found"
💥 现象
这个坑比较隐蔽。用浏览器打开页面,一切正常。但用curl看页面源码——
$ curl -s https://v2.smallfiredragon.com/science/xxx | grep not-found
<div class="not-found">...
源码里有not-found标记。搜索引擎爬虫看到的就是这个源码,这意味着SEO直接废了。
🔍 排查
Nuxt 3的SSR是这么工作的:Node服务端先渲染一遍HTML发给浏览器,然后客户端拿到HTML后再"hydrate"(激活),客户端会重新fetch数据。
问题出在服务端渲染这一步。Node进程在服务器内部fetch CMS API时,走的域名是v2.smallfiredragon.com——但服务器自己解析不到这个域名(DNS没配内网解析)。所以服务端fetch失败,渲染出了not-found状态。
浏览器为什么正常?因为客户端hydrate后重新fetch,走的是公网DNS,能解析到,所以又获取到了数据,覆盖了服务端的错误状态。用户看不出来,但爬虫看到的是服务端那份错误的HTML。
🎯 根因
SSR环境下的网络请求和客户端完全不同。服务端在内网,DNS解析、防火墙规则、hosts文件都可能不一样。这个差异在开发环境里根本测不出来,因为开发机上什么都能解析。
🔧 修复
两种方案:在服务器的/etc/hosts里加一条域名解析记录,或者在Nuxt的runtimeConfig里把SSR端的API地址改成内网回环地址(127.0.0.1:8370)。我们两个都做了,双保险。
📝 教训
部署SSR应用,一定要用curl检查服务端渲染出来的HTML。浏览器看到的≠搜索引擎看到的。curl才是爬虫的视角。每次部署后跑一遍curl检查,是SSR项目的必修课。
坑4:汉堡菜单"隐身"了
💥 现象
手机端打开网站,右上角应该有个汉堡菜单图标——但什么都看不见。不是没渲染,是渲染了但看不见。
🔍 排查
打开DevTools一看,元素在那里,有宽高,位置也对。打开Computed看颜色:#94A3B8,一个偏冷的中灰色。背景色?#111318,深蓝黑色。
数字上对比度勉强过线,但实际在手机小屏上看,细线条图标配上这个灰色——真的很难注意到。尤其是在户外强光下或者屏幕亮度偏低的时候,约等于隐身。
🎯 根因
深色主题下的交互元素颜色没有做专项审查。桌面端大屏上可能勉强能看,手机端小屏就直接"消失"了。
🔧 修复
把图标颜色改成品牌橙#F97316。橙色在深色背景上对比度拉满,而且和品牌色统一,一举两得。
📝 教训
深色主题不是把背景改黑就完了。每个交互元素都要重新审视颜色对比度。建议上线前用WebAIM的Contrast Checker跑一遍所有可交互元素,尤其是图标、按钮边框、次级文字这些容易忽略的地方。
坑5:老板的提醒被当耳旁风了
💥 现象
下午17:53,老板在群里发了一句:"注意文章路径是否一样"。
团队的反应:检查了一下HTTP状态码,200,没问题!继续搞别的去了。
然后就出了坑2和坑3。
🔍 排查
回过头看,老板说的"注意文章路径"其实暗含了好几层意思:路径能不能访问?访问了返回什么?内容对不对?SEO路径有没有变?旧链接还能不能跳转?
但团队只理解了最表面的一层:"路径能访问" → HTTP 200 → 没问题。
🎯 根因
HTTP 200只代表"服务器正常响应了",不代表"页面内容是对的"。一个显示"文章不存在"的页面,照样返回200。
🔧 修复
没有代码修复,这是流程问题。后来团队定了一条规矩:老板的提醒 = 风险信号,必须深入排查到内容层。不是检查状态码就完了,而是要打开页面看内容、看源码、测交互。
📝 教训
200 OK是最不可靠的"一切正常"信号。验收必须看实际内容,不是看状态码。这一条不止适用于架构迁移——任何部署后的检查都一样。
SFD编者注
这5个坑,每一个单独拿出来看都不难修。但叠在一起,再加上"一天搞定"的时间压力,就变成了一场事故接力赛。
我们实验室这次迁移最大的收获不是技术层面的——Nginx配置、Mock数据清理、DNS解析,这些搜一下都能查到。最大的收获是对"验收"这件事的重新理解:
你以为验收是打开首页看一眼。实际上验收是模拟用户的完整操作路径,包括那些你觉得"肯定没问题"的页面。
尤其是架构迁移这种事,改的是地基。地基一换,上面的每一层楼、每一扇窗、每一根水管都可能受影响。不能只检查大门能不能开,要每个房间都走一遍。
📋 架构迁移检查清单
最后整理了一份清单,我们内部在用,分享出来:
一、迁移前
- □ 列出旧站所有静态资源路径(/uploads/、/images/、/fonts/、/assets/等)
- □ 列出旧站所有API接口地址
- □ 列出旧站所有文章/页面URL,导出一份完整URL清单
- □ grep全项目"mock"、"fake"、"dummy"、"test"关键词,标记所有待替换的假数据
- □ 确认新架构的服务端能否解析所有必需域名(curl测试,不要用浏览器)
- □ 确认CMS API的参数格式(lang、slug等字段的命名和值)
- □ 备份旧站配置(Nginx conf、DNS记录、SSL证书路径)
二、Nginx配置切换
- □ 为每个静态资源路径添加独立的location block
- □ API转发单独配location(不要混在主proxy_pass里)
- □ 测试每个location block是否生效(curl每个路径)
- □ 检查SSL证书是否正确绑定到新配置
- □ 旧URL做301重定向到新URL(如果路径结构有变化)
三、SSR专项检查
- □ 用curl检查首页源码,确认有实际内容(不是空壳或not-found)
- □ 用curl检查至少3个文章详情页源码
- □ 确认服务端DNS能解析所有API域名(在服务器上nslookup/dig测试)
- □ 检查SSR环境变量是否正确设置(API地址、语言参数等)
- □ 对比服务端渲染结果和客户端渲染结果,不应有内容差异
四、内容与UI验收
- □ 打开首页,检查所有图片是否加载
- □ 点进至少3篇文章详情页,确认内容正常显示
- □ 测试所有语言版本(中/英/日等),确认切换正常
- □ 手机端测试:汉堡菜单、导航、文章页、图片
- □ 检查所有交互元素在深色/浅色主题下的可见性
- □ 检查页面title、meta description、OG tags是否正确
五、上线后监控
- □ 旧URL全量测试(用导出的URL清单跑一遍,检查是否301/200)
- □ Google Search Console检查索引状态(上线后1-3天)
- □ 监控服务器错误日志(Nginx error log + Node进程日志)
- □ 让团队外的人(或老板)随意浏览,发现你漏掉的问题
这份清单不长,但每一条都是我们用真实翻车换来的。建议存下来,下次架构迁移前打开对一遍。
毕竟,踩坑不可怕,可怕的是同一个坑踩两次。