个人博客 SEO 优化实战:Next.js 与 Vercel 完整指南

个人博客部署到 Vercel 后,页面能正常打开,并不代表 Google 已经理解和收录了它。搜索引擎需要知道哪些 URL 应该抓取、每个页面讲什么、不同语言页面之间是什么关系,以及哪个地址是正式版本。

这篇文章以一个使用 Next.js App Router、MDX、zh / en 路由并部署在 Vercel 的个人博客为例,整理一套不依赖独立业务后端的 SEO 实施方案。


一、没有后端会影响 SEO 吗?

不会。SEO 关心的是搜索引擎访问 URL 时能否获得稳定、可理解的 HTML,而不是项目是否拥有数据库或传统后端。

Next.js 可以通过服务端渲染、静态生成和 Server Components 输出完整正文。只要文章标题、正文和链接已经存在于返回的 HTML 中,Google 就不需要等待复杂的客户端请求才能理解页面。

真正需要避免的是:初始 HTML 只有一个空容器,必须执行大量 JavaScript、请求接口后才显示主要内容。对于以 MDX 为内容源的博客,让文章在构建或服务端阶段生成通常更简单,也更适合搜索引擎。

二、先确定唯一的正式域名

所有 SEO URL 都应该基于同一个生产域名:

export const siteConfig = {
  url: "https://odiv-three.vercel.app",
  name: "oDiv",
}

这个地址会用于:

  • canonical URL
  • Open Graph URL
  • sitemap 中的文章地址
  • robots.txt 中的 sitemap 地址
  • JSON-LD 中的作者与文章标识

如果同一内容可以从自定义域名、www 域名和 Vercel 域名访问,应选择一个主域名,并把其他域名永久重定向过去。不要让同一篇文章长期存在多个可索引地址。

将来更换自定义域名时,只修改集中配置,并同步更新重定向、canonical、sitemap 和 Search Console 属性。

三、为每个页面生成独立 Metadata

全站共用一个标题是最常见的博客 SEO 问题之一。首页、博客列表、项目页和每篇文章都应该拥有独立的 titledescription

App Router 可以使用 metadatagenerateMetadata

export async function generateMetadata({params}: Props): Promise<Metadata> {
  const {locale, slug} = await params
  const {metadata} = await getMdxPost(locale, slug)

  return {
    title: metadata.title,
    description: metadata.description,
  }
}

文章标题应准确表达搜索意图。例如,“学习笔记”很难告诉用户内容是什么,而“Next.js App Router 浏览器通知与权限处理”更加明确。

描述不需要堆叠关键词。用一到两句话说明文章解决的问题、技术范围和读者能够获得的结果即可。

四、正确处理 canonical 与双语页面

canonical 用来声明当前页面的正式 URL。例如中文文章应该指向自己的中文地址:

<link
  rel="canonical"
  href="https://odiv-three.vercel.app/zh/blog/personal-blog-seo-optimization"
/>

英文文章也应该 canonical 到自己的英文地址,而不是指向中文页面。中英文关系通过 hreflang 表达:

<link rel="alternate" hreflang="zh" href="https://odiv-three.vercel.app/zh/blog/personal-blog-seo-optimization" />
<link rel="alternate" hreflang="en" href="https://odiv-three.vercel.app/en/blog/personal-blog-seo-optimization" />
<link rel="alternate" hreflang="x-default" href="https://odiv-three.vercel.app/zh/blog/personal-blog-seo-optimization" />

同时确保初始 HTML 使用正确的语言标记:

<html lang={locale}>

这三个信号共同帮助搜索引擎区分正式地址、中文版本和英文版本。

五、生成 sitemap.xml

博客文章会不断增加,不适合手动维护 XML。使用 app/sitemap.ts 从 MDX 元数据动态生成 URL:

export default async function sitemap(): Promise<MetadataRoute.Sitemap> {
  const posts = await listMdxPosts("zh")

  return posts.map((post) => ({
    url: `https://odiv-three.vercel.app/zh/blog/${post.slug}`,
    lastModified: new Date(post.updatedAt ?? post.date),
    changeFrequency: "monthly",
  }))
}

实际项目还应包含中英文首页、博客列表、关于、项目和工具页面,并过滤 draft: true 的文章。

不要把这些地址加入 sitemap:

  • API 路由
  • 404 页面
  • Vercel Preview Deployment
  • 草稿文章
  • 只是筛选状态的查询参数 URL

lastModified 应来自真实的 updatedAt 或发布日期,不要为了看起来更新频繁而在每次请求时填写当前时间。

六、提供 robots.txt

app/robots.ts 可以明确允许公开页面并声明 sitemap:

export default function robots(): MetadataRoute.Robots {
  return {
    rules: {
      userAgent: "*",
      allow: "/",
      disallow: ["/api/"],
    },
    sitemap: "https://odiv-three.vercel.app/sitemap.xml",
  }
}

不要禁止 /_next/ 下的样式和脚本。Google 需要这些资源正确渲染页面。robots.txt 也不是处理重复内容的工具;重复 URL 应使用重定向与 canonical。

七、为文章添加结构化数据

在文章页输出 BlogPosting JSON-LD,可以明确表达标题、作者、日期、语言和正文页面:

const jsonLd = {
  "@context": "https://schema.org",
  "@type": "BlogPosting",
  headline: metadata.title,
  description: metadata.description,
  datePublished: metadata.date,
  dateModified: metadata.updatedAt ?? metadata.date,
  author: {
    "@type": "Person",
    name: "oDiv",
  },
}

<script
  type="application/ld+json"
  dangerouslySetInnerHTML={{
    __html: JSON.stringify(jsonLd).replace(/</g, "\\u003c"),
  }}
/>

还可以增加 BreadcrumbList,表达“首页 → 博客 → 当前文章”的层级。结构化数据不会保证排名,但能减少搜索引擎理解页面时的歧义,并为富媒体搜索结果提供基础。

八、使用 Vercel 域名接入 Search Console

如果当前使用 odiv-three.vercel.app,无法修改整个 vercel.app 的 DNS,因此应在 Google Search Console 中添加“网址前缀”属性:

https://odiv-three.vercel.app/

可以选择 HTML 文件或 meta 标签验证。使用环境变量保存 Google 提供的验证码:

GOOGLE_SITE_VERIFICATION=google提供的验证码

然后通过 Next.js Metadata 输出验证标签。部署完成后提交:

https://odiv-three.vercel.app/sitemap.xml

使用 URL Inspection 检查首页、博客列表和几篇重要文章。对单个新页面可以请求编入索引,大量文章则应依靠 sitemap。

九、内容和内部链接决定长期表现

技术配置解决的是“能否被发现和理解”,并不保证文章能够排到前面。个人博客更需要持续积累清晰、真实且有搜索需求的内容。

一篇技术文章至少应该做到:

  1. 围绕一个具体问题或搜索意图。
  2. 标题直接描述问题与技术范围。
  3. 只有一个主要 h1,并使用 h2h3 组织结构。
  4. 提供可复现的代码、错误现象、版本和限制条件。
  5. 链接到站内相关主题文章。
  6. 为图片提供准确的替代文本。
  7. 内容变化后更新 updatedAt,而不是只修改日期。

可以围绕一个核心主题建立内容集群。例如以 Next.js SEO 为中心,继续写 metadata、动态 OG 图片、多语言路由、性能优化和 Search Console 排错,让文章之间形成自然的内部链接。

十、部署后的验证清单

每次重要 SEO 改动上线后,手动检查:

/robots.txt
/sitemap.xml
/zh
/en
/zh/blog/personal-blog-seo-optimization
/en/blog/personal-blog-seo-optimization

在页面源码中确认:

  • 标题和描述是否与页面内容一致
  • canonical 是否指向当前正式 URL
  • zhenx-default 是否互相对应
  • <html lang> 是否正确
  • 文章日期、作者和 JSON-LD 是否存在
  • 页面是否返回 200,不存在的文章是否返回 404
  • robots.txt 和 meta 标签是否没有意外的 noindex

最后使用 Google Rich Results Test、Search Console URL Inspection 和移动端 PageSpeed Insights 检查搜索引擎看到的最终结果。

总结

Next.js 个人博客不需要独立后端也能获得良好的 SEO。完整的基础方案包括:

  • 服务端或构建时输出正文
  • 唯一生产域名
  • 独立的页面标题与描述
  • self-canonical 与双语 hreflang
  • 自动生成的 sitemap 和 robots
  • BlogPosting 与面包屑结构化数据
  • Search Console 验证与持续监控
  • 对真实问题有帮助的原创内容和内部链接

SEO 不是一次性开关。先确保搜索引擎能够正确抓取和理解,再通过持续发布、更新和互相连接的内容积累长期搜索表现。

参考资料