首页 / 文章

Next.js 应用路由器中的技术 SEO:元数据、站点地图与 JSON-LD

了解共享元数据辅助工具、默认根布局、robots.ts文件、动态站点地图、规范的JSON-LD格式以及页面审计如何为Next.js应用奠定良好的SEO基础。

发布者:REACTAPP.TOP阅读约 4 分钟1024 词

来源: How I Got a Next.js Project to 100% SEO on Lighthouse

一个 Next.js 应用看似已经完成,但搜索引擎仍可能难以理解其内容:页面缺乏规范 URL,爬虫规则未定义,新内容也从未被加入站点地图。本指南以一个包含大量资源页面的模拟数据 API 网站为例,从首次 Lighthouse SEO 检测时的低分逐步提升至 100 分,展示了如何利用 App Router 内置的元数据 API 完成这七项改进。

通过一个辅助函数生成页面元数据

在每个页面中手动编写元数据容易导致问题,比如某个页面缺少规范 URL,另一个页面的 Open Graph 标题过时。一个简单的工具可以解决这个问题:每个页面只需提供标题、描述、路径以及可选的 noIndex 标志,该辅助函数便会将其扩展为规范 URL、机器人协议设置和 Open Graph 相关字段:

export function createPageMetadata({
  title,
  description,
  path,
  noIndex = false,
}: PageMetadata) {
  return {
    title,
    description,
    alternates: {
      canonical: path,
    },
    robots: noIndex ? "noindex, nofollow" : "index, follow",
    openGraph: {
      title,
      description,
      url: path,
      type: "website",
    },
  };
}

索引设置是可选的:通过一个标志即可将页面设置为noindex, nofollow状态。由于path是相对路径,该辅助功能依赖于根布局中定义的基准URL。

将全站默认值放在根布局中

所有需要在整个站点中共用的内容都应包含在layout.tsx的metadata导出中:

  • metadataBase
  • 标题模板
  • 默认描述
  • Open Graph默认设置
  • Twitter卡片配置
  • robots协议默认值
  • <html>元素上的lang属性

该导出的简化版本如下:

export const metadata: Metadata = {
  metadataBase: new URL("https://mockdata.ir"),
  title: {
    default: "MockData",
    template: "%s | MockData",
  },
  description: "...",
};

使用 %s | MockData 模板时,标题为“Users API”的页面会显示为“Users API | MockData”,而无标题的页面则使用 default 值。metadataBase 负责将辅助函数中的相对 canonical 和 Open Graph url 值转换为绝对 URL。需要注意的是,lang 并非元数据字段;应在布局渲染的 <html> 标签上设置该值。

使用 robots.ts 定义爬虫规则

无需让爬虫规则保持未定义状态,只需从返回类型为 MetadataRoute.Robots 对象的 app/robots.ts 文件中生成 robots.txt 即可:

export default function robots(): MetadataRoute.Robots {
  return {
    rules: {
      userAgent: "*",
      allow: "/",
    },
    sitemap: "https://mockdata.ir/sitemap.xml",
  };
}

该文件被刻意设计得极为简单:所有用户代理均可爬取所有内容,同时还会标注站点地图的位置。

根据数据生成站点地图

由于存在针对用户、文章、产品等内容的资源页面,手动维护的 XML 站点地图难以扩展。sitemap.ts 的默认导出可以是 async 类型,这样它就可以查询这些页面所使用的同一数据源:

export default async function sitemap(): Promise<MetadataRoute.Sitemap> {
  const resources = await getPublicResources();

return [
    {
      url: "https://mockdata.ir",
      lastModified: new Date(),
    },
    ...resources.map((resource) => ({
      url: `https://mockdata.ir/${resource.slug}`,
      lastModified: resource.updatedAt,
    })),
  ];
}

每个资源都会对应一个 URL,其中 updatedAt 被用作 lastModified,因此新的公开资源会自动加入站点地图。还有一个改进点:首页使用 new Date() 会声称每次生成时都有变化,而使用真实的内容时间戳则更为准确。

仅在确实需要时添加结构化数据

结合 Schema.org 词汇表的 JSON-LD 能让搜索引擎了解页面的含义。该应用本身被描述为 SoftwareApplication,所使用的类型包括:

  • WebSite
  • Organization
  • SoftwareApplication
  • BreadcrumbList
  • 要追求准确性而非数量:标记内容必须描述页面上实际存在的元素。编造的评论、评分或其他虚构属性具有误导性,可能违反搜索引擎规范。

    确保界面与结构化数据中的面包屑路径一致

    嵌套的文档页面会显示如首页 → 文档 → 用户API这样的可见路径,而BreadcrumbList结构化数据也会输出相同的层级结构。可见路径与标记内容应始终描述同一结构。

    手动审核每一个可索引页面

    最后,需逐一检查每个公开页面:

    • 它是否有且仅有一个明确的H1标题?
    • 标题是否准确描述了该页面的内容?
    • 描述内容是否与实际内容相符?
    • 该页面是否有有用的内链指向其他页面或来自其他页面?
  • 是否应该将此页面纳入索引?
  • 是否有任何空页或价值较低的页面暴露给爬虫?
  • 并非所有路径都适合出现在搜索结果中;使用noindex通常是正确的选择。关于标题结构,可参考这篇关于语义化HTML的指南以了解相关标记方法。

    完美的Lighthouse SEO评分意味着什么以及不意味着什么

    完成这些修复后,Lighthouse显示的SEO评分为100分。该分数用于检测标题、描述和可爬取性等技术基础问题,但与页面排名无关。排名取决于内容质量、用户搜索意图、网站权威性、外链数量、竞争情况、性能以及许多其他因素。

    真正的价值在于打好了基础。在发布任何Next.js应用之前进行审计成本很低,却能发现许多小错误。

    核心要点

    • 将每页的元数据集中管理在辅助函数中,并在根布局中设置共享的默认值,包括metadataBase。
    • 使用robots.ts和异步的sitemap.ts,以确保爬虫规则与URL能与数据保持同步。
    • 仅添加能够真实描述页面的结构化数据,并确保界面与模式中的导航路径完全一致。
    • 对于不应出现在搜索结果中的页面,可将noindex视为一种合理的选择。
    • 将Lighthouse评分100视为“技术上合格”,而非排名有保障的标志。