10.Next的Seo实践
会员专享 · 非会员仅可阅读 30% 的正文。
- 发布时间
- February 16, 2025
- 阅读时间
- 10 min read
- 作者
- Felix
- 访问
- 会员专享
非会员仅可阅读 30% 的正文。
1. Meta标签
Next App Router比较主流的有两种定义源数据标签的方式,一种是通过在布局或者页面上导出一个 metadata 的对象,会自动生成对应的Meta源数据标签,这是静态的。
而另外一种则是动态生成meta标签,这种场景通常需要先请求接口得到一些信息的动态源数据页面,在这种情况下我们采用generateMetadata函数。
1.1. 静态Meta标签
仅仅只需要在页面或者布局中添加这一段。
export const metadata: Metadata = {
metadataBase: new URL(APP_ORIGIN),
title: APP_TITLE,
description: APP_DESCRIPTION,
creator: APP_NAME,
icons: {
icon: '/favicon.ico',
shortcut: '/favicon.ico'
},
openGraph: {
title: APP_TITLE,
description: APP_DESCRIPTION,
url: APP_ORIGIN,
siteName: APP_NAME,
images: [
{
url: OG_URL,
width: 2880,
height: 1800,
alt: APP_NAME
}
],
type: 'website',
locale: 'en_US'
},
twitter: {
card: 'summary_large_image',
site: TWITTER_SOCIAL_URL,
title: APP_TITLE,
description: APP_DESCRIPTION,
images: {
url: '/og.jpg',
width: 2880,
height: 1800,
alt: APP_NAME
}
}
}1.2. 生成的HTML Meta标签
上面的 metadata 对象会被 Next.js 自动转换为相应的 HTML meta 标签。假设我们的应用配置如下:
const APP_ORIGIN = 'https://example.com'
const APP_TITLE = 'My Awesome App'
const APP_DESCRIPTION = 'This is an awesome app built with Next.js'
const APP_NAME = 'AwesomeApp'
const OG_URL = 'https://example.com/og-image.jpg'
const TWITTER_SOCIAL_URL = '@awesome_app'那么,生成的 HTML head 部分可能会包含以下 meta 标签:
<head>
<title>My Awesome App</title>
<meta name="description" content="This is an awesome app built with Next.js" />
<meta name="creator" content="AwesomeApp" />
<link rel="icon" href="/favicon.ico" />
<link rel="shortcut icon" href="/favicon.ico" />
<!-- Open Graph tags -->
<meta property="og:title" content="My Awesome App" />
<meta property="og:description" content="This is an awesome app built with Next.js" />
<meta property="og:url" content="https://example.com" />
<meta property="og:site_name" content="AwesomeApp" />
<meta property="og:image" content="https://example.com/og-image.jpg" />
<meta property="og:image:width" content="2880" />
<meta property="og:image:height" content="1800" />
<meta property="og:image:alt" content="AwesomeApp" />
<meta property="og:type" content="website" />
<meta property="og:locale" content="en_US" />
<!-- Twitter Card tags -->
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:site" content="@awesome_app" />
<meta name="twitter:title" content="My Awesome App" />
<meta name="twitter:description" content="This is an awesome app built with Next.js" />
<meta name="twitter:image" content="https://example.com/og.jpg" />
<meta name="twitter:image:width" content="2880" />
<meta name="twitter:image:height" content="1800" />
<meta name="twitter:image:alt" content="AwesomeApp" />
</head>这些生成的 meta 标签包含了我们在 metadata 对象中定义的所有信息,包括基本的页面信息、Open Graph 标签和 Twitter Card 标签。这些标签可以极大地提升我们的网页在搜索引擎结果中的展示效果,以及在社交媒体平台上的分享效果。
1.3. 动态Meta标签
对于需要根据动态数据生成元数据的页面,我们可以使用generateMetadata函数。这种方法特别适用于博客文章、产品详情页面等内容随时间或用户输入变化的场景。
示例代码:
import type { Metadata } from 'next'
type Props = {
params: { id: string }
}
export async function generateMetadata({ params }: Props): Promise<Metadata> {
// 从API获取数据
const product = await fetch(`https://api.acme.com/products/${params.id}`).then((res) => res.json())
return {
title: product.name,
description: product.description,
openGraph: {
title: `${product.name} - Acme Products`,
description: product.description,
images: [{ url: product.image }]
}
}
}
export default function Page({ params }: Props) {
// ...
}这个函数允许我们基于动态数据(如API响应)生成元数据,确保每个页面都有独特且相关的SEO信息。
1.4 generateMetadata的流式渲染
流式渲染指的就是不用等待整个ssr中的请求完毕再抛出document,通过 Transfer-Encoding: chunked 的请求头标识把整个document文档进行分块传输,来进行优化页面内容传输以及提升用户体验。
generateMetadata 函数不会触发 Suspense,我的猜测这是由于其设计和实现方式导致的。以下是几个主要原因:
服务器端执行:
generateMetadata主要在服务器端执行,而 Suspense 主要用于客户端渲染中处理异步操作。元数据的关键性:元数据对于SEO非常重要,Next优先考虑确保元数据在初始 HTML 中可用,而不是延迟加载。
渲染顺序:元数据通常需要在页面内容之前生成,因为它们位于 HTML 的
<head>部分。这使得难以将其纳入 Suspense 的流式渲染模型中。兼容性考虑:不是所有的客户端(如搜索引擎爬虫)都能处理通过 JavaScript 动态插入的元数据。
这种设计导致了一些潜在的性能问题:
- 阻塞渲染:如果
generateMetadata函数执行时间较长,它会延迟整个页面的渲染。 - 无法并行加载:元数据生成和页面内容加载无法并行进行,可能会增加总体加载时间。
- 客户端导航延迟:在客户端导航时,新页面的渲染可能会因为等待元数据生成而被延迟。
为了解决这些问题,Next引入了"流式元数据"(Streaming Metadata)功能。这个新特性旨在提高页面加载速度,特别是在处理慢速元数据生成时,但只能在canary中使用。
流式元数据的主要优势:
- 非阻塞渲染:
generateMetadata返回的元数据被视为可挂起的数据,允许页面内容立即渲染。 - 异步注入:元数据在解析完成后,会在客户端异步注入到页面中。
- SEO友好:对于搜索引擎爬虫,仍然会在HTML中接收完全渲染的元数据。
- 用户体验优先:对于人类用户,他们主要关心页面内容,元数据可以稍后添加而不影响他们的体验。
如何使用:
要启用流式元数据功能,你需要在 next.config.js 中添加以下配置:
module.exports = {
experimental: {
streamingMetadata: true
}
}注意事项:
- 这个功能默认是禁用的,需要手动开启。
- 对于某些有限的机器人(如不能处理JavaScript的爬虫),你可以使用
experimental.htmlLimitedBots选项来指定它们应该接收完全阻塞的元数据,但我目前的做法是用正则匹配了市面主流的所有爬虫。 - 默认情况下,只有能够像无头浏览器一样运行的Google机器人会在启用此功能时接收流式元数据。
为什么这个解决方案很重要:
- 性能提升:通过允许页面内容先渲染,然后异步加载元数据,可以显著提高感知加载速度。
- 更好的用户体验:用户可以更快地看到和交互页面内容,而不必等待所有元数据加载完成。
- SEO和用户体验的平衡:通过为搜索引擎爬虫提供完整的元数据,同时为人类用户优化加载速度,实现了SEO和用户体验的完美平衡。
1.5 generateMetadata和页面组件的请求优化
在使用 generateMetadata 和页面组件时,一个常见的担忧是可能会导致重复的数据请求。因为 generateMetadata 和页面组件可能需要相同的数据。
请求重复问题
考虑以下场景:
import type { Metadata } from 'next'
async function getData(id: string) {
const res = await fetch(`https://api.example.com/product/${id}`)
return res.json()
}
export async function generateMetadata({ params }: { params: { id: string } }): Promise<Metadata> {
const product = await getData(params.id)
return { title: product.name }
}
export default async function Page({ params }: { params: { id: string } }) {
const product = await getData(params.id)
return <h1>{product.name}</h1>
}乍看之下,似乎 getData 函数会被调用两次:一次在 generateMetadata 中,另一次在页面组件中。
Next.js 的请求去重优化
但Next.js 已经内置了请求去重优化。在同一个路由段(route segment)内,具有相同参数的重复请求会被自动去重。这意味着:
getData函数实际上只会被调用一次。- 第一次调用(通常是在
generateMetadata中)的结果会被缓存。 - 后续的调用(在页面组件中)会直接使用缓存的结果,而不会触发新的网络请求。
2. robots.txt
2.1. robots.txt 的重要性和基本概念
robots.txt 文件是网站与搜索引擎爬虫之间的一种通信机制。它位于网站的根目录,作为网站管理员向搜索引擎爬虫传达爬取指令的第一道关卡。正确配置 robots.txt 可以:
- 指导爬虫如何爬取网站内容
- 防止敏感或不必要的页面被索引
- 优化网站的爬取效率
- 间接影响网站的 SEO 表现
在 Next.js 应用中,我们有两种方式来实现 robots.txt:静态文件方法和动态生成方法。每种方法都有其特定的使用场景和优势。
2.2. 静态Robots.txt
静态文件方法是最直观的实现方式。你只需在public/目录下创建一个名为 robots.txt 的文件。
例如,一个基本的 robots.txt 文件可能如下所示:
User-Agent: *
Allow: /
Disallow: /admin/
Disallow: /private/
Sitemap: https://www.yourwebsite.com/sitemap.xml让我们逐行解析这个文件:
User-Agent: *:这一行表示以下规则适用于所有的搜索引擎爬虫。Allow: /:允许爬虫访问网站的所有页面(除非被后续规则覆盖)。Disallow: /admin/:禁止爬虫访问/admin/目录及其子目录。Disallow: /private/:同样禁止爬虫访问/private/目录及其子目录。Sitemap: https://www.yourwebsite.com/sitemap.xml:指明网站 Sitemap 的位置,帮助搜索引擎更好地了解网站结构。
静态文件方法的优点是简单直接,适合网站结构相对固定、不需要频繁更新 robots.txt 内容的情况。
2.3. 动态生成
Next.js
订阅后解锁完整文章
支持创作、解锁全文,未来更新也会第一时间送达。
评论
加入讨论
还没有评论,来占个沙发吧。