Next.js元数据与SEO #

一、元数据基础 #

1.1 元数据概念 #

元数据是用于描述网页的信息,包括标题、描述、关键词等,对SEO和社交分享至关重要。

1.2 静态元数据 #

tsx
import type { Metadata } from 'next'

export const metadata: Metadata = {
    title: '我的网站',
    description: '这是一个使用 Next.js 构建的网站',
}

export default function Page() {
    return <div>页面内容</div>
}

1.3 动态元数据 #

tsx
import type { Metadata } from 'next'

interface PageProps {
    params: Promise<{ slug: string }>
}

export async function generateMetadata({ params }: PageProps): Promise<Metadata> {
    const { slug } = await params
    const post = await getPost(slug)
    
    return {
        title: post.title,
        description: post.excerpt,
    }
}

export default function Page({ params }: PageProps) {
    return <div>页面内容</div>
}

二、元数据字段 #

2.1 基本字段 #

tsx
import type { Metadata } from 'next'

export const metadata: Metadata = {
    title: '页面标题',
    description: '页面描述',
    keywords: ['Next.js', 'React', 'JavaScript'],
    authors: [{ name: '作者名' }],
    creator: '创建者',
    publisher: '发布者',
    robots: {
        index: true,
        follow: true,
    },
}

2.2 标题模板 #

tsx
export const metadata: Metadata = {
    title: {
        default: '我的网站',
        template: '%s | 我的网站',
    },
}

子页面使用:

tsx
export const metadata: Metadata = {
    title: '关于我们',
}

生成结果:关于我们 | 我的网站

2.3 图标配置 #

tsx
export const metadata: Metadata = {
    icons: {
        icon: '/favicon.ico',
        shortcut: '/favicon-16x16.png',
        apple: '/apple-touch-icon.png',
    },
}

2.4 manifest #

tsx
export const metadata: Metadata = {
    manifest: '/manifest.json',
}

三、Open Graph #

3.1 基本配置 #

tsx
import type { Metadata } from 'next'

export const metadata: Metadata = {
    openGraph: {
        title: '页面标题',
        description: '页面描述',
        url: 'https://example.com/page',
        siteName: '网站名称',
        images: [
            {
                url: 'https://example.com/og-image.png',
                width: 1200,
                height: 630,
                alt: '图片描述',
            },
        ],
        locale: 'zh_CN',
        type: 'website',
    },
}

3.2 文章类型 #

tsx
export const metadata: Metadata = {
    openGraph: {
        title: '文章标题',
        description: '文章描述',
        type: 'article',
        publishedTime: '2024-01-01',
        authors: ['作者名'],
        tags: ['Next.js', 'React'],
        images: [
            {
                url: 'https://example.com/article-image.png',
                width: 1200,
                height: 630,
            },
        ],
    },
}

3.3 动态Open Graph #

tsx
interface PageProps {
    params: Promise<{ slug: string }>
}

export async function generateMetadata({ params }: PageProps): Promise<Metadata> {
    const { slug } = await params
    const post = await getPost(slug)
    
    return {
        title: post.title,
        description: post.excerpt,
        openGraph: {
            title: post.title,
            description: post.excerpt,
            type: 'article',
            publishedTime: post.publishedAt,
            authors: [post.author.name],
            images: [
                {
                    url: post.coverImage,
                    width: 1200,
                    height: 630,
                    alt: post.title,
                },
            ],
        },
    }
}

四、Twitter卡片 #

4.1 基本配置 #

tsx
import type { Metadata } from 'next'

export const metadata: Metadata = {
    twitter: {
        card: 'summary_large_image',
        title: '页面标题',
        description: '页面描述',
        creator: '@twitter_handle',
        images: ['https://example.com/twitter-image.png'],
    },
}

4.2 卡片类型 #

类型 说明
summary 小图片摘要卡片
summary_large_image 大图片摘要卡片
player 视频/音频播放器
app 应用卡片

4.3 完整示例 #

tsx
export const metadata: Metadata = {
    twitter: {
        card: 'summary_large_image',
        site: '@site_handle',
        creator: '@creator_handle',
        title: '文章标题',
        description: '文章描述',
        images: [
            {
                url: 'https://example.com/twitter-image.png',
                width: 1200,
                height: 630,
                alt: '图片描述',
            },
        ],
    },
}

五、其他SEO配置 #

5.1 规范链接 #

tsx
export const metadata: Metadata = {
    alternates: {
        canonical: 'https://example.com/page',
        languages: {
            'zh-CN': 'https://example.com/zh/page',
            'en-US': 'https://example.com/en/page',
        },
    },
}

5.2 站点地图 #

tsx
import { MetadataRoute } from 'next'

export default function sitemap(): MetadataRoute.Sitemap {
    return [
        {
            url: 'https://example.com',
            lastModified: new Date(),
            changeFrequency: 'daily',
            priority: 1,
        },
        {
            url: 'https://example.com/about',
            lastModified: new Date(),
            changeFrequency: 'monthly',
            priority: 0.8,
        },
        {
            url: 'https://example.com/blog',
            lastModified: new Date(),
            changeFrequency: 'weekly',
            priority: 0.9,
        },
    ]
}

5.3 robots.txt #

tsx
import { MetadataRoute } from 'next'

export default function robots(): MetadataRoute.Robots {
    return {
        rules: {
            userAgent: '*',
            allow: '/',
            disallow: ['/api/', '/admin/'],
        },
        sitemap: 'https://example.com/sitemap.xml',
    }
}

5.4 结构化数据 #

tsx
export default function ProductPage({ product }) {
    const jsonLd = {
        '@context': 'https://schema.org',
        '@type': 'Product',
        name: product.name,
        description: product.description,
        image: product.image,
        offers: {
            '@type': 'Offer',
            price: product.price,
            priceCurrency: 'CNY',
            availability: 'https://schema.org/InStock',
        },
    }
    
    return (
        <>
            <script
                type="application/ld+json"
                dangerouslySetInnerHTML={{ __html: JSON.stringify(jsonLd) }}
            />
            <div>产品内容</div>
        </>
    )
}

六、完整示例 #

6.1 博客文章页面 #

tsx
import type { Metadata } from 'next'
import { MetadataRoute } from 'next'

interface PageProps {
    params: Promise<{ slug: string }>
}

export async function generateMetadata({ params }: PageProps): Promise<Metadata> {
    const { slug } = await params
    const post = await getPost(slug)
    
    return {
        title: post.title,
        description: post.excerpt,
        keywords: post.tags,
        authors: [{ name: post.author.name }],
        openGraph: {
            title: post.title,
            description: post.excerpt,
            type: 'article',
            publishedTime: post.publishedAt,
            modifiedTime: post.updatedAt,
            authors: [post.author.name],
            tags: post.tags,
            images: [
                {
                    url: post.coverImage,
                    width: 1200,
                    height: 630,
                    alt: post.title,
                },
            ],
        },
        twitter: {
            card: 'summary_large_image',
            title: post.title,
            description: post.excerpt,
            images: [post.coverImage],
        },
        alternates: {
            canonical: `https://example.com/blog/${post.slug}`,
        },
    }
}

export default async function BlogPost({ params }: PageProps) {
    const { slug } = await params
    const post = await getPost(slug)
    
    const jsonLd = {
        '@context': 'https://schema.org',
        '@type': 'BlogPosting',
        headline: post.title,
        description: post.excerpt,
        image: post.coverImage,
        datePublished: post.publishedAt,
        dateModified: post.updatedAt,
        author: {
            '@type': 'Person',
            name: post.author.name,
        },
    }
    
    return (
        <>
            <script
                type="application/ld+json"
                dangerouslySetInnerHTML={{ __html: JSON.stringify(jsonLd) }}
            />
            <article>
                <h1>{post.title}</h1>
                <div>{post.content}</div>
            </article>
        </>
    )
}

6.2 产品页面 #

tsx
import type { Metadata } from 'next'

interface PageProps {
    params: Promise<{ id: string }>
}

export async function generateMetadata({ params }: PageProps): Promise<Metadata> {
    const { id } = await params
    const product = await getProduct(id)
    
    return {
        title: product.name,
        description: product.description,
        openGraph: {
            title: product.name,
            description: product.description,
            type: 'product',
            images: [
                {
                    url: product.image,
                    width: 800,
                    height: 800,
                    alt: product.name,
                },
            ],
        },
        twitter: {
            card: 'summary_large_image',
            title: product.name,
            description: product.description,
            images: [product.image],
        },
    }
}

export default async function ProductPage({ params }: PageProps) {
    const { id } = await params
    const product = await getProduct(id)
    
    const jsonLd = {
        '@context': 'https://schema.org',
        '@type': 'Product',
        name: product.name,
        description: product.description,
        image: product.image,
        brand: {
            '@type': 'Brand',
            name: product.brand,
        },
        offers: {
            '@type': 'Offer',
            price: product.price,
            priceCurrency: 'CNY',
            availability: product.inStock
                ? 'https://schema.org/InStock'
                : 'https://schema.org/OutOfStock',
        },
    }
    
    return (
        <>
            <script
                type="application/ld+json"
                dangerouslySetInnerHTML={{ __html: JSON.stringify(jsonLd) }}
            />
            <div>产品内容</div>
        </>
    )
}

七、最佳实践 #

7.1 元数据继承 #

布局中的元数据会被子页面继承:

tsx
export const metadata: Metadata = {
    title: {
        default: '我的网站',
        template: '%s | 我的网站',
    },
    description: '网站描述',
    openGraph: {
        siteName: '我的网站',
    },
}

7.2 合并策略 #

tsx
export const metadata: Metadata = {
    title: '页面标题',
    openGraph: {
        title: 'OG标题',
    },
}

7.3 图片优化 #

tsx
export const metadata: Metadata = {
    openGraph: {
        images: [
            {
                url: '/og-image.png',
                width: 1200,
                height: 630,
                alt: '描述',
            },
        ],
    },
}

八、总结 #

元数据与SEO要点:

要点 说明
静态元数据 export const metadata
动态元数据 generateMetadata函数
Open Graph 社交分享优化
Twitter卡片 Twitter分享优化
结构化数据 搜索引擎理解内容
站点地图 搜索引擎索引

下一步,让我们学习导航与链接!

最后更新:2026-03-28