SSR页面动态内容SEO无法抓取怎么办?
我在用Next.js做SSR优化时遇到个奇怪的问题。页面用getStaticProps请求了API数据,本地开发和生产环境访问都能正常显示动态内容,但Google Search Console里显示抓取的HTML里这部分数据全是空的。已经检查过SSG配置和meta标签都没问题,甚至用curl模拟爬虫请求也看到数据正常渲染了。
搞不懂的是为什么SEO工具(比如Screaming Frog)抓取时这部分内容就消失了?是不是SSR生成的静态文件没包含异步数据?尝试过在export async function getStaticProps()里加了setTimeout模拟延迟,结果反而能被抓取到,这说明什么问题呢?
export async function getStaticProps() {
const res = await fetch('https://api.example.com/data');
const data = await res.json();
return { props: { items: data }, revalidate: 10 };
}
先说结论:你用的
revalidate: 10是 ISR(增量静态再生),它的工作机制是「首次请求时生成静态页,之后每次请求在后台判断是否过期,过期就后台重新生成」,但关键点来了——生成的静态文件只在有用户访问时才会触发再生,不是你一部署就立刻生成好所有版本的。你本地和生产环境能正常显示,是因为你手动访问了页面,触发了ISR的“首次渲染”,数据被塞进HTML里了;但Google爬虫第一次来的时候,如果恰好这个页面还没生成过(或者缓存失效了但还没来得及重新生成),它拿到的就是一个「空壳」HTML,只有静态结构,没有动态数据。
你用
setTimeout反而能被抓取到,是因为加了延迟,把爬虫的请求时间拖长了,恰好赶上了数据渲染完成的时机——这不是解决方案,是误打误撞。那怎么办?分三步走:
第一步:确认你部署后有没有真正触发过页面的首次渲染
你得手动访问一下每个需要SEO的页面路径,或者写个脚本在部署后“预热”一下。比如你有个
/products/[id]的动态页,部署完别光等爬虫来,自己先请求一遍,让ISR先生成好静态页。第二步:如果页面量大、路径多,手动预热不现实,那就用
getServerSideProps做兜底(或者临时方案)比如对关键页面,比如首页、产品页,先改成SSR,至少能保证每次请求都有数据。代码改这样:
这玩意儿是每次请求都实时查数据再渲染,SEO肯定能抓到,只是性能比SSG差一点。如果你页面访问量不大,或者对首屏延迟不敏感,先这么干最省心。
第三步:真想坚持用ISR,那就得加「预渲染保障」
比如你用Vercel部署,可以写一个
vercel.json配置预渲染路径:然后新建一个
pages/api/prerender.js,在API里统一预渲染所有需要SEO的页面:不过说实话,这个方案太重了,大多数项目根本用不上。更简单的做法是——在Vercel里用
stale-while-revalidate的方式,直接让页面在生成后立刻被缓存,别让它过早失效。回到你的代码,把
revalidate: 10改成一个更大的值,比如60 * 60(一小时),或者干脆去掉这个字段,变成纯SSG(静态生成):纯SSG的页面是构建时就生成好HTML的,爬虫来的时候肯定有数据,不会出现空内容。唯一代价是数据更新需要重新部署。
最后说个实战经验:Google Search Console 里看到的“抓取内容为空”,有时候不是真的空,而是它还没来得及执行JS渲染(比如你用了
useEffect加载数据,但没加loading状态,导致HTML里没内容)。不过你既然用curl能看到数据,就排除了这个可能。总结一下:
- 先确认页面有没有被真实访问过(预热)
- 关键页面先用
getServerSideProps兜底- 要坚持ISR就别设太短的
revalidate- 实在不行,用纯SSG,构建时生成好HTML
你试试先从第二步开始,把关键页面改成
getServerSideProps,部署后过几分钟再用 Google Search Console 看,基本就能解决问题了。有问题随时回来问,我这边调试过类似问题十几次,基本都是这几种原因。首先你要明确的是,
getStaticProps是 Next.js 用来做静态生成(SSG)的方法,它的特点是会在构建时预先生成静态 HTML 文件。也就是说,当你运行next build的时候,Next.js 会调用getStaticProps方法,把返回的数据嵌入到静态文件中。如果这个过程出问题了,那么最终生成的 HTML 就会缺少动态数据,导致 SEO 工具抓取不到这些内容。第一步:检查 API 请求是否在构建时成功
你需要确认
getStaticProps中的 API 请求在构建时是否能正常完成。因为很多开发者容易忽略一个问题:有些 API 在开发环境下可以正常访问,但在构建环境中可能由于网络限制、认证问题或者环境变量配置错误而失败。你可以通过在
getStaticProps中加一些日志输出来确认:如果你发现构建时 API 请求失败了,那问题就出在这里。你需要确保 API 地址在构建环境中是可访问的,比如使用绝对路径而不是相对路径,或者检查环境变量是否正确配置。
第二步:理解
revalidate的作用你代码里用了
revalidate: 10,这表示启用了增量静态生成(ISR)。也就是说,页面会在第一次请求后每 10 秒重新生成一次。但这里有个关键点:在构建时生成的初始静态文件中,必须包含完整的数据。如果构建时数据为空,那么即使 ISR 后续更新了数据,SEO 工具抓取到的仍然是空的内容。所以,你需要确保构建时的数据是完整的。如果 API 数据在构建时不可用,你可以考虑在构建时使用 mock 数据,或者延迟部署直到数据准备好。
第三步:模拟爬虫行为测试
你提到用
curl模拟爬虫请求时能看到数据正常渲染,但 SEO 工具抓取时却看不到。这可能是因为 SEO 工具的行为和普通爬虫不太一样,它们可能会设置特定的 User-Agent 或者其他请求头。你可以用以下命令模拟更真实的爬虫行为:如果这时候抓取到的 HTML 中仍然没有数据,那说明问题还是出在静态文件生成阶段。
第四步:尝试用
getServerSideProps替代如果以上方法都解决不了问题,你可以考虑用
getServerSideProps替代getStaticProps。两者的区别在于,getServerSideProps是在每次请求时动态生成页面,而不是在构建时生成静态文件。这样可以确保 SEO 工具抓取时总是能拿到最新的数据。代码改写如下:
不过需要注意的是,
getServerSideProps会增加服务器的负载,因为它每次都需要实时请求 API。如果你的页面访问量很大,可能需要权衡一下性能和 SEO 的需求。第五步:排查构建环境的问题
有时候问题并不是代码本身,而是构建环境的问题。比如,CI/CD 环境中可能缺少某些依赖,或者构建脚本执行顺序有问题。你可以试着在本地运行
next build && next export,然后检查生成的静态文件中是否有数据。如果本地没问题,但线上有问题,那就需要检查 CI/CD 配置了。看看是不是构建过程中有网络超时、API 不可用等问题。
总结一下
1. 首先确认
getStaticProps中的 API 请求在构建时是否成功。2. 确保构建时生成的静态文件中包含完整的数据。
3. 如果问题依然存在,可以尝试用
getServerSideProps替代。4. 最后排查构建环境的配置问题。
希望这些步骤能帮你解决问题!如果还有疑问,可以继续讨论。