site-architecture

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Site Architecture Skill

网站架构技能

Load with: base.md + web-content.md
For technical website structure that enables discovery by search engines AND AI crawlers (GPTBot, ClaudeBot, PerplexityBot).

加载依赖:base.md + web-content.md
适用于可被搜索引擎和AI爬虫(GPTBot、ClaudeBot、PerplexityBot)发现的技术型网站架构。

Philosophy

理念

Content is king. Architecture is the kingdom.
Great content buried in poor architecture won't be discovered. This skill covers the technical foundation that makes your content findable by:
  • Google, Bing (traditional search)
  • GPTBot (ChatGPT), ClaudeBot, PerplexityBot (AI assistants)
  • Social platforms (Open Graph, Twitter Cards)

内容为王,架构为疆。
优质内容如果被糟糕的架构埋没,就无法被发现。本技能涵盖让你的内容被以下渠道发现的技术基础:
  • Google、Bing(传统搜索引擎)
  • GPTBot(ChatGPT)、ClaudeBot、PerplexityBot(AI助手)
  • 社交平台(Open Graph、Twitter Cards)

robots.txt

robots.txt

Basic Template

基础模板

txt
undefined
txt
undefined

robots.txt

robots.txt

Allow all crawlers by default

默认允许所有爬虫

User-agent: * Allow: / Disallow: /api/ Disallow: /admin/ Disallow: /private/ Disallow: /_next/ Disallow: /cdn-cgi/
User-agent: * Allow: / Disallow: /api/ Disallow: /admin/ Disallow: /private/ Disallow: /_next/ Disallow: /cdn-cgi/

Sitemap location

站点地图位置

Crawl delay (optional - be careful, not all bots respect this)

爬取延迟(可选 - 注意,并非所有爬虫都遵循此规则)

Crawl-delay: 1

Crawl-delay: 1

undefined
undefined

AI Bot Configuration

AI爬虫配置

txt
undefined
txt
undefined

robots.txt with AI bot rules

包含AI爬虫规则的robots.txt

=== SEARCH ENGINES ===

=== 搜索引擎 ===

User-agent: Googlebot Allow: /
User-agent: Bingbot Allow: /
User-agent: Googlebot Allow: /
User-agent: Bingbot Allow: /

=== AI ASSISTANTS (Allow for discovery) ===

=== AI助手(允许爬取以实现内容发现) ===

User-agent: GPTBot Allow: /
User-agent: ChatGPT-User Allow: /
User-agent: Claude-Web Allow: /
User-agent: ClaudeBot Allow: /
User-agent: PerplexityBot Allow: /
User-agent: Amazonbot Allow: /
User-agent: anthropic-ai Allow: /
User-agent: Google-Extended Allow: /
User-agent: GPTBot Allow: /
User-agent: ChatGPT-User Allow: /
User-agent: Claude-Web Allow: /
User-agent: ClaudeBot Allow: /
User-agent: PerplexityBot Allow: /
User-agent: Amazonbot Allow: /
User-agent: anthropic-ai Allow: /
User-agent: Google-Extended Allow: /

=== BLOCK AI TRAINING (Optional - block training, allow chat) ===

=== 阻止AI训练(可选 - 允许引用但禁止用于训练) ===

Uncomment these if you want to be cited but not used for training

如果你希望内容被引用但不用于训练,取消以下注释

User-agent: CCBot

User-agent: CCBot

Disallow: /

Disallow: /

User-agent: GPTBot

User-agent: GPTBot

Disallow: / # Blocks both chat and training

Disallow: / # 同时阻止聊天和训练用途

=== BLOCK SCRAPERS ===

=== 阻止数据抓取工具 ===

User-agent: AhrefsBot Disallow: /
User-agent: SemrushBot Disallow: /
User-agent: MJ12bot Disallow: /
User-agent: AhrefsBot Disallow: /
User-agent: SemrushBot Disallow: /
User-agent: MJ12bot Disallow: /

=== DEFAULT ===

=== 默认规则 ===

User-agent: * Allow: / Disallow: /api/ Disallow: /admin/ Disallow: /auth/ Disallow: /private/ Disallow: /.json$ Disallow: /?*
undefined
User-agent: * Allow: / Disallow: /api/ Disallow: /admin/ Disallow: /auth/ Disallow: /private/ Disallow: /.json$ Disallow: /?*
undefined

Next.js robots.txt

Next.js 版本 robots.txt

typescript
// app/robots.ts
import { MetadataRoute } from 'next';

export default function robots(): MetadataRoute.Robots {
  const baseUrl = process.env.NEXT_PUBLIC_URL || 'https://yoursite.com';

  return {
    rules: [
      {
        userAgent: '*',
        allow: '/',
        disallow: ['/api/', '/admin/', '/private/', '/_next/'],
      },
      {
        userAgent: 'GPTBot',
        allow: '/',
      },
      {
        userAgent: 'ClaudeBot',
        allow: '/',
      },
      {
        userAgent: 'PerplexityBot',
        allow: '/',
      },
    ],
    sitemap: `${baseUrl}/sitemap.xml`,
  };
}

typescript
// app/robots.ts
import { MetadataRoute } from 'next';

export default function robots(): MetadataRoute.Robots {
  const baseUrl = process.env.NEXT_PUBLIC_URL || 'https://yoursite.com';

  return {
    rules: [
      {
        userAgent: '*',
        allow: '/',
        disallow: ['/api/', '/admin/', '/private/', '/_next/'],
      },
      {
        userAgent: 'GPTBot',
        allow: '/',
      },
      {
        userAgent: 'ClaudeBot',
        allow: '/',
      },
      {
        userAgent: 'PerplexityBot',
        allow: '/',
      },
    ],
    sitemap: `${baseUrl}/sitemap.xml`,
  };
}

Sitemap

站点地图(Sitemap)

XML Sitemap Template

XML站点地图模板

xml
<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"
        xmlns:news="http://www.google.com/schemas/sitemap-news/0.9"
        xmlns:image="http://www.google.com/schemas/sitemap-image/1.1">
  <url>
    <loc>https://yoursite.com/</loc>
    <lastmod>2025-01-15</lastmod>
    <changefreq>weekly</changefreq>
    <priority>1.0</priority>
  </url>
  <url>
    <loc>https://yoursite.com/pricing</loc>
    <lastmod>2025-01-10</lastmod>
    <changefreq>monthly</changefreq>
    <priority>0.9</priority>
  </url>
  <url>
    <loc>https://yoursite.com/blog/article-slug</loc>
    <lastmod>2025-01-12</lastmod>
    <changefreq>monthly</changefreq>
    <priority>0.8</priority>
    <image:image>
      <image:loc>https://yoursite.com/images/article-image.jpg</image:loc>
    </image:image>
  </url>
</urlset>
xml
<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"
        xmlns:news="http://www.google.com/schemas/sitemap-news/0.9"
        xmlns:image="http://www.google.com/schemas/sitemap-image/1.1">
  <url>
    <loc>https://yoursite.com/</loc>
    <lastmod>2025-01-15</lastmod>
    <changefreq>weekly</changefreq>
    <priority>1.0</priority>
  </url>
  <url>
    <loc>https://yoursite.com/pricing</loc>
    <lastmod>2025-01-10</lastmod>
    <changefreq>monthly</changefreq>
    <priority>0.9</priority>
  </url>
  <url>
    <loc>https://yoursite.com/blog/article-slug</loc>
    <lastmod>2025-01-12</lastmod>
    <changefreq>monthly</changefreq>
    <priority>0.8</priority>
    <image:image>
      <image:loc>https://yoursite.com/images/article-image.jpg</image:loc>
    </image:image>
  </url>
</urlset>

Next.js Dynamic Sitemap

Next.js 动态站点地图

typescript
// app/sitemap.ts
import { MetadataRoute } from 'next';

export default async function sitemap(): Promise<MetadataRoute.Sitemap> {
  const baseUrl = process.env.NEXT_PUBLIC_URL || 'https://yoursite.com';

  // Static pages
  const staticPages = [
    { url: '/', priority: 1.0, changeFrequency: 'weekly' as const },
    { url: '/pricing', priority: 0.9, changeFrequency: 'monthly' as const },
    { url: '/about', priority: 0.8, changeFrequency: 'monthly' as const },
    { url: '/contact', priority: 0.7, changeFrequency: 'yearly' as const },
  ];

  // Dynamic pages (e.g., blog posts)
  const posts = await getBlogPosts(); // Your data fetching function
  const blogPages = posts.map((post) => ({
    url: `/blog/${post.slug}`,
    lastModified: new Date(post.updatedAt),
    changeFrequency: 'monthly' as const,
    priority: 0.8,
  }));

  return [
    ...staticPages.map((page) => ({
      url: `${baseUrl}${page.url}`,
      lastModified: new Date(),
      changeFrequency: page.changeFrequency,
      priority: page.priority,
    })),
    ...blogPages.map((page) => ({
      url: `${baseUrl}${page.url}`,
      lastModified: page.lastModified,
      changeFrequency: page.changeFrequency,
      priority: page.priority,
    })),
  ];
}
typescript
// app/sitemap.ts
import { MetadataRoute } from 'next';

export default async function sitemap(): Promise<MetadataRoute.Sitemap> {
  const baseUrl = process.env.NEXT_PUBLIC_URL || 'https://yoursite.com';

  // 静态页面
  const staticPages = [
    { url: '/', priority: 1.0, changeFrequency: 'weekly' as const },
    { url: '/pricing', priority: 0.9, changeFrequency: 'monthly' as const },
    { url: '/about', priority: 0.8, changeFrequency: 'monthly' as const },
    { url: '/contact', priority: 0.7, changeFrequency: 'yearly' as const },
  ];

  // 动态页面(如博客文章)
  const posts = await getBlogPosts(); // 你的数据获取函数
  const blogPages = posts.map((post) => ({
    url: `/blog/${post.slug}`,
    lastModified: new Date(post.updatedAt),
    changeFrequency: 'monthly' as const,
    priority: 0.8,
  }));

  return [
    ...staticPages.map((page) => ({
      url: `${baseUrl}${page.url}`,
      lastModified: new Date(),
      changeFrequency: page.changeFrequency,
      priority: page.priority,
    })),
    ...blogPages.map((page) => ({
      url: `${baseUrl}${page.url}`,
      lastModified: page.lastModified,
      changeFrequency: page.changeFrequency,
      priority: page.priority,
    })),
  ];
}

Sitemap Index (Large Sites)

站点地图索引(大型站点适用)

xml
<?xml version="1.0" encoding="UTF-8"?>
<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
  <sitemap>
    <loc>https://yoursite.com/sitemap-pages.xml</loc>
    <lastmod>2025-01-15</lastmod>
  </sitemap>
  <sitemap>
    <loc>https://yoursite.com/sitemap-blog.xml</loc>
    <lastmod>2025-01-14</lastmod>
  </sitemap>
  <sitemap>
    <loc>https://yoursite.com/sitemap-products.xml</loc>
    <lastmod>2025-01-13</lastmod>
  </sitemap>
</sitemapindex>

xml
<?xml version="1.0" encoding="UTF-8"?>
<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
  <sitemap>
    <loc>https://yoursite.com/sitemap-pages.xml</loc>
    <lastmod>2025-01-15</lastmod>
  </sitemap>
  <sitemap>
    <loc>https://yoursite.com/sitemap-blog.xml</loc>
    <lastmod>2025-01-14</lastmod>
  </sitemap>
  <sitemap>
    <loc>https://yoursite.com/sitemap-products.xml</loc>
    <lastmod>2025-01-13</lastmod>
  </sitemap>
</sitemapindex>

Meta Tags

元标签(Meta Tags)

Essential Meta Tags

必备元标签

html
<head>
  <!-- Basic -->
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Page Title | Brand Name</title>
  <meta name="description" content="Compelling 150-160 character description with keywords and CTA.">

  <!-- Canonical (prevent duplicate content) -->
  <link rel="canonical" href="https://yoursite.com/current-page">

  <!-- Language -->
  <html lang="en">
  <meta name="language" content="English">

  <!-- Robots -->
  <meta name="robots" content="index, follow">
  <meta name="googlebot" content="index, follow">

  <!-- Author -->
  <meta name="author" content="Author Name">

  <!-- Favicon -->
  <link rel="icon" href="/favicon.ico" sizes="any">
  <link rel="icon" href="/icon.svg" type="image/svg+xml">
  <link rel="apple-touch-icon" href="/apple-touch-icon.png">
  <link rel="manifest" href="/manifest.webmanifest">
</head>
html
<head>
  <!-- 基础设置 -->
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>页面标题 | 品牌名称</title>
  <meta name="description" content="150-160字符的有吸引力描述,包含关键词和行动号召。">

  <!-- 规范链接(避免重复内容) -->
  <link rel="canonical" href="https://yoursite.com/current-page">

  <!-- 语言设置 -->
  <html lang="en">
  <meta name="language" content="English">

  <!-- 爬虫规则 -->
  <meta name="robots" content="index, follow">
  <meta name="googlebot" content="index, follow">

  <!-- 作者信息 -->
  <meta name="author" content="作者姓名">

  <!-- 网站图标 -->
  <link rel="icon" href="/favicon.ico" sizes="any">
  <link rel="icon" href="/icon.svg" type="image/svg+xml">
  <link rel="apple-touch-icon" href="/apple-touch-icon.png">
  <link rel="manifest" href="/manifest.webmanifest">
</head>

Open Graph (Social Sharing)

Open Graph(社交分享)

html
<!-- Open Graph / Facebook -->
<meta property="og:type" content="website">
<meta property="og:url" content="https://yoursite.com/page">
<meta property="og:title" content="Page Title - Brand">
<meta property="og:description" content="Description for social sharing (can be longer).">
<meta property="og:image" content="https://yoursite.com/og-image.jpg">
<meta property="og:image:width" content="1200">
<meta property="og:image:height" content="630">
<meta property="og:site_name" content="Brand Name">
<meta property="og:locale" content="en_US">

<!-- Article-specific (for blog posts) -->
<meta property="og:type" content="article">
<meta property="article:published_time" content="2025-01-15T08:00:00Z">
<meta property="article:modified_time" content="2025-01-20T10:00:00Z">
<meta property="article:author" content="https://yoursite.com/team/author">
<meta property="article:section" content="Technology">
<meta property="article:tag" content="AI, SEO, Content">
html
<!-- Open Graph / Facebook -->
<meta property="og:type" content="website">
<meta property="og:url" content="https://yoursite.com/page">
<meta property="og:title" content="页面标题 - 品牌">
<meta property="og:description" content="用于社交分享的描述(可更长)。">
<meta property="og:image" content="https://yoursite.com/og-image.jpg">
<meta property="og:image:width" content="1200">
<meta property="og:image:height" content="630">
<meta property="og:site_name" content="品牌名称">
<meta property="og:locale" content="en_US">

<!-- 文章专属设置(适用于博客文章) -->
<meta property="og:type" content="article">
<meta property="article:published_time" content="2025-01-15T08:00:00Z">
<meta property="article:modified_time" content="2025-01-20T10:00:00Z">
<meta property="article:author" content="https://yoursite.com/team/author">
<meta property="article:section" content="Technology">
<meta property="article:tag" content="AI, SEO, Content">

Twitter Cards

Twitter 卡片

html
<!-- Twitter -->
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:site" content="@yourbrand">
<meta name="twitter:creator" content="@authorhandle">
<meta name="twitter:title" content="Page Title">
<meta name="twitter:description" content="Description for Twitter (max 200 chars).">
<meta name="twitter:image" content="https://yoursite.com/twitter-image.jpg">
html
<!-- Twitter -->
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:site" content="@yourbrand">
<meta name="twitter:creator" content="@authorhandle">
<meta name="twitter:title" content="页面标题">
<meta name="twitter:description" content="Twitter分享描述(最多200字符)。">
<meta name="twitter:image" content="https://yoursite.com/twitter-image.jpg">

Next.js Metadata

Next.js 元数据配置

typescript
// app/layout.tsx
import { Metadata } from 'next';

export const metadata: Metadata = {
  metadataBase: new URL('https://yoursite.com'),
  title: {
    default: 'Brand Name',
    template: '%s | Brand Name',
  },
  description: 'Your default site description.',
  keywords: ['keyword1', 'keyword2', 'keyword3'],
  authors: [{ name: 'Brand Name', url: 'https://yoursite.com' }],
  creator: 'Brand Name',
  publisher: 'Brand Name',
  robots: {
    index: true,
    follow: true,
    googleBot: {
      index: true,
      follow: true,
      'max-video-preview': -1,
      'max-image-preview': 'large',
      'max-snippet': -1,
    },
  },
  openGraph: {
    type: 'website',
    locale: 'en_US',
    url: 'https://yoursite.com',
    siteName: 'Brand Name',
    title: 'Brand Name',
    description: 'Your site description.',
    images: [
      {
        url: '/og-image.jpg',
        width: 1200,
        height: 630,
        alt: 'Brand Name',
      },
    ],
  },
  twitter: {
    card: 'summary_large_image',
    site: '@yourbrand',
    creator: '@yourbrand',
  },
  verification: {
    google: 'google-verification-code',
    yandex: 'yandex-verification-code',
  },
};

// app/blog/[slug]/page.tsx
export async function generateMetadata({ params }): Promise<Metadata> {
  const post = await getPost(params.slug);

  return {
    title: post.title,
    description: post.excerpt,
    openGraph: {
      title: post.title,
      description: post.excerpt,
      type: 'article',
      publishedTime: post.publishedAt,
      modifiedTime: post.updatedAt,
      authors: [post.author.name],
      images: [post.coverImage],
    },
  };
}

typescript
// app/layout.tsx
import { Metadata } from 'next';

export const metadata: Metadata = {
  metadataBase: new URL('https://yoursite.com'),
  title: {
    default: '品牌名称',
    template: '%s | 品牌名称',
  },
  description: '你的默认网站描述。',
  keywords: ['keyword1', 'keyword2', 'keyword3'],
  authors: [{ name: '品牌名称', url: 'https://yoursite.com' }],
  creator: '品牌名称',
  publisher: '品牌名称',
  robots: {
    index: true,
    follow: true,
    googleBot: {
      index: true,
      follow: true,
      'max-video-preview': -1,
      'max-image-preview': 'large',
      'max-snippet': -1,
    },
  },
  openGraph: {
    type: 'website',
    locale: 'en_US',
    url: 'https://yoursite.com',
    siteName: '品牌名称',
    title: '品牌名称',
    description: '你的网站描述。',
    images: [
      {
        url: '/og-image.jpg',
        width: 1200,
        height: 630,
        alt: '品牌名称',
      },
    ],
  },
  twitter: {
    card: 'summary_large_image',
    site: '@yourbrand',
    creator: '@yourbrand',
  },
  verification: {
    google: 'google-verification-code',
    yandex: 'yandex-verification-code',
  },
};

// app/blog/[slug]/page.tsx
export async function generateMetadata({ params }): Promise<Metadata> {
  const post = await getPost(params.slug);

  return {
    title: post.title,
    description: post.excerpt,
    openGraph: {
      title: post.title,
      description: post.excerpt,
      type: 'article',
      publishedTime: post.publishedAt,
      modifiedTime: post.updatedAt,
      authors: [post.author.name],
      images: [post.coverImage],
    },
  };
}

URL Structure

URL 结构

Best Practices

最佳实践

markdown
✅ GOOD URLs:
/blog/ai-seo-best-practices
/products/pro-plan
/pricing
/about/team

❌ BAD URLs:
/blog?id=123
/p/12345
/index.php?page=about
/Products/Pro_Plan (inconsistent casing)
markdown
✅ 优质URL示例:
/blog/ai-seo-best-practices
/products/pro-plan
/pricing
/about/team

❌ 不良URL示例:
/blog?id=123
/p/12345
/index.php?page=about
/Products/Pro_Plan(大小写不一致)

URL Guidelines

URL 规范

RuleExample
Lowercase only
/blog/my-post
not
/Blog/My-Post
Hyphens not underscores
/my-page
not
/my_page
No trailing slashes
/about
not
/about/
Descriptive slugs
/pricing
not
/p
No query params for content
/blog/post-title
not
/blog?id=123
Max 3-4 levels deep
/blog/category/post
规则示例
仅使用小写字母
/blog/my-post
而非
/Blog/My-Post
使用连字符而非下划线
/my-page
而非
/my_page
末尾无斜杠
/about
而非
/about/
描述性路径段
/pricing
而非
/p
内容页面不使用查询参数
/blog/post-title
而非
/blog?id=123
深度不超过3-4层
/blog/category/post

Redirect Configuration

重定向配置

typescript
// next.config.js
module.exports = {
  async redirects() {
    return [
      // Redirect old URLs to new
      {
        source: '/old-page',
        destination: '/new-page',
        permanent: true, // 301 redirect
      },
      // Redirect with wildcard
      {
        source: '/blog/old/:slug',
        destination: '/articles/:slug',
        permanent: true,
      },
      // Trailing slash redirect
      {
        source: '/:path+/',
        destination: '/:path+',
        permanent: true,
      },
    ];
  },
};

typescript
// next.config.js
module.exports = {
  async redirects() {
    return [
      // 将旧URL重定向到新URL
      {
        source: '/old-page',
        destination: '/new-page',
        permanent: true, // 301永久重定向
      },
      // 通配符重定向
      {
        source: '/blog/old/:slug',
        destination: '/articles/:slug',
        permanent: true,
      },
      // 末尾斜杠重定向
      {
        source: '/:path+/',
        destination: '/:path+',
        permanent: true,
      },
    ];
  },
};

Canonical URLs

规范链接(Canonical URLs)

Implementation

实现方式

html
<!-- Always include canonical, even for primary URL -->
<link rel="canonical" href="https://yoursite.com/current-page">
html
<!-- 始终包含规范链接,即使页面只有一个版本 -->
<link rel="canonical" href="https://yoursite.com/current-page">

When to Use

使用场景

markdown
✅ USE CANONICAL:
- Every page (even if only version exists)
- Paginated content (point to page 1 or use rel=prev/next)
- URL parameters that don't change content (?utm_source=...)
- HTTP vs HTTPS (canonical to HTTPS)
- www vs non-www (pick one, canonical to it)

Example: /products?sort=price should canonical to /products
markdown
✅ 应使用规范链接的场景:
- 每个页面(即使只有一个版本)
- 分页内容(指向第1页或使用rel=prev/next)
- 不改变内容的URL参数(如?utm_source=...)
- HTTP与HTTPS(规范到HTTPS)
- www与非www域名(选择其一,规范到该域名)

示例:/products?sort=price 应规范到 /products

Next.js Canonical

Next.js 规范链接配置

typescript
// Automatic in metadata
export const metadata: Metadata = {
  alternates: {
    canonical: '/current-page',
  },
};

typescript
// 在元数据中自动配置
export const metadata: Metadata = {
  alternates: {
    canonical: '/current-page',
  },
};

Security Headers

安全头

Essential Headers

必备头信息

typescript
// next.config.js
const securityHeaders = [
  {
    key: 'X-DNS-Prefetch-Control',
    value: 'on',
  },
  {
    key: 'Strict-Transport-Security',
    value: 'max-age=63072000; includeSubDomains; preload',
  },
  {
    key: 'X-Frame-Options',
    value: 'SAMEORIGIN',
  },
  {
    key: 'X-Content-Type-Options',
    value: 'nosniff',
  },
  {
    key: 'Referrer-Policy',
    value: 'strict-origin-when-cross-origin',
  },
  {
    key: 'Permissions-Policy',
    value: 'camera=(), microphone=(), geolocation=()',
  },
];

module.exports = {
  async headers() {
    return [
      {
        source: '/:path*',
        headers: securityHeaders,
      },
    ];
  },
};

typescript
// next.config.js
const securityHeaders = [
  {
    key: 'X-DNS-Prefetch-Control',
    value: 'on',
  },
  {
    key: 'Strict-Transport-Security',
    value: 'max-age=63072000; includeSubDomains; preload',
  },
  {
    key: 'X-Frame-Options',
    value: 'SAMEORIGIN',
  },
  {
    key: 'X-Content-Type-Options',
    value: 'nosniff',
  },
  {
    key: 'Referrer-Policy',
    value: 'strict-origin-when-cross-origin',
  },
  {
    key: 'Permissions-Policy',
    value: 'camera=(), microphone=(), geolocation=()',
  },
];

module.exports = {
  async headers() {
    return [
      {
        source: '/:path*',
        headers: securityHeaders,
      },
    ];
  },
};

Core Web Vitals

核心网页指标(Core Web Vitals)

Target Metrics

目标指标

MetricGoodNeeds ImprovementPoor
LCP (Largest Contentful Paint)≤2.5s≤4.0s>4.0s
INP (Interaction to Next Paint)≤200ms≤500ms>500ms
CLS (Cumulative Layout Shift)≤0.1≤0.25>0.25
指标优秀需要改进较差
LCP(最大内容绘制)≤2.5秒≤4.0秒>4.0秒
INP(交互到下一次绘制)≤200毫秒≤500毫秒>500毫秒
CLS(累积布局偏移)≤0.1≤0.25>0.25

Optimization Checklist

优化检查清单

markdown
undefined
markdown
undefined

LCP (Loading)

LCP(加载性能)

  • Optimize largest image (WebP, proper sizing)
  • Preload critical assets
  • Use CDN for static assets
  • Enable compression (gzip/brotli)
  • Minimize render-blocking resources
  • 优化最大图片(WebP格式、合适尺寸)
  • 预加载关键资源
  • 为静态资源使用CDN
  • 启用压缩(gzip/brotli)
  • 最小化阻塞渲染的资源

INP (Interactivity)

INP(交互性能)

  • Minimize JavaScript execution time
  • Break up long tasks
  • Use web workers for heavy computation
  • Optimize event handlers
  • Lazy load non-critical JS
  • 最小化JavaScript执行时间
  • 拆分长任务
  • 使用Web Workers处理重型计算
  • 优化事件处理器
  • 懒加载非关键JS

CLS (Visual Stability)

CLS(视觉稳定性)

  • Set dimensions on images/videos
  • Reserve space for dynamic content
  • Avoid inserting content above existing
  • Use transform for animations
  • Preload fonts
undefined
  • 为图片/视频设置尺寸
  • 为动态内容预留空间
  • 避免在现有内容上方插入新内容
  • 使用transform实现动画
  • 预加载字体
undefined

Next.js Performance

Next.js 性能优化

typescript
// Image optimization
import Image from 'next/image';

<Image
  src="/hero.jpg"
  alt="Hero image"
  width={1200}
  height={630}
  priority // Preload for LCP
  placeholder="blur"
  blurDataURL={blurDataUrl}
/>

// Font optimization
import { Inter } from 'next/font/google';

const inter = Inter({
  subsets: ['latin'],
  display: 'swap', // Prevent FOIT
});

// Dynamic imports
import dynamic from 'next/dynamic';

const HeavyComponent = dynamic(() => import('./HeavyComponent'), {
  loading: () => <Skeleton />,
  ssr: false, // Client-only if needed
});

typescript
// 图片优化
import Image from 'next/image';

<Image
  src="/hero.jpg"
  alt="Hero image"
  width={1200}
  height={630}
  priority // 为LCP预加载
  placeholder="blur"
  blurDataURL={blurDataUrl}
/>

// 字体优化
import { Inter } from 'next/font/google';

const inter = Inter({
  subsets: ['latin'],
  display: 'swap', // 避免FOIT(字体加载前不可见文本)
});

// 动态导入
import dynamic from 'next/dynamic';

const HeavyComponent = dynamic(() => import('./HeavyComponent'), {
  loading: () => <Skeleton />,
  ssr: false, // 如需仅在客户端渲染
});

Internal Linking

内部链接

Structure

结构

markdown
undefined
markdown
undefined

Link Architecture

链接架构

Homepage ├── /pricing (1 click) ├── /features (1 click) ├── /blog (1 click) │ ├── /blog/category-1 (2 clicks) │ │ └── /blog/category-1/post (3 clicks) │ └── /blog/category-2 (2 clicks) └── /about (1 click)
Rule: Every page within 3 clicks of homepage
undefined
首页 ├── /pricing(1次点击) ├── /features(1次点击) ├── /blog(1次点击) │ ├── /blog/category-1(2次点击) │ │ └── /blog/category-1/post(3次点击) │ └── /blog/category-2(2次点击) └── /about(1次点击)
规则:所有页面需在3次点击内从首页到达
undefined

Best Practices

最佳实践

markdown
✅ DO:
- Use descriptive anchor text
- Link contextually within content
- Create hub pages for topics
- Link to related content at end of posts
- Use breadcrumbs for navigation

❌ AVOID:
- "Click here" as anchor text
- Orphan pages (no internal links)
- Too many links per page (>100)
- Broken internal links
- Redirect chains
markdown
✅ 推荐做法:
- 使用描述性锚文本
- 在内容中上下文关联链接
- 创建主题中心页面
- 在文章末尾链接到相关内容
- 使用面包屑导航

❌ 避免做法:
- 使用“点击这里”作为锚文本
- 孤立页面(无内部链接)
- 单页面链接过多(>100个)
- 无效内部链接
- 重定向链

Breadcrumbs

面包屑导航

typescript
// components/Breadcrumbs.tsx
import Link from 'next/link';

interface BreadcrumbItem {
  name: string;
  href: string;
}

export function Breadcrumbs({ items }: { items: BreadcrumbItem[] }) {
  const jsonLd = {
    '@context': 'https://schema.org',
    '@type': 'BreadcrumbList',
    itemListElement: items.map((item, index) => ({
      '@type': 'ListItem',
      position: index + 1,
      name: item.name,
      item: `https://yoursite.com${item.href}`,
    })),
  };

  return (
    <>
      <script
        type="application/ld+json"
        dangerouslySetInnerHTML={{ __html: JSON.stringify(jsonLd) }}
      />
      <nav aria-label="Breadcrumb">
        <ol className="flex gap-2">
          {items.map((item, index) => (
            <li key={item.href}>
              {index > 0 && <span>/</span>}
              <Link href={item.href}>{item.name}</Link>
            </li>
          ))}
        </ol>
      </nav>
    </>
  );
}

typescript
// components/Breadcrumbs.tsx
import Link from 'next/link';

interface BreadcrumbItem {
  name: string;
  href: string;
}

export function Breadcrumbs({ items }: { items: BreadcrumbItem[] }) {
  const jsonLd = {
    '@context': 'https://schema.org',
    '@type': 'BreadcrumbList',
    itemListElement: items.map((item, index) => ({
      '@type': 'ListItem',
      position: index + 1,
      name: item.name,
      item: `https://yoursite.com${item.href}`,
    })),
  };

  return (
    <>
      <script
        type="application/ld+json"
        dangerouslySetInnerHTML={{ __html: JSON.stringify(jsonLd) }}
      />
      <nav aria-label="Breadcrumb">
        <ol className="flex gap-2">
          {items.map((item, index) => (
            <li key={item.href}>
              {index > 0 && <span>/</span>}
              <Link href={item.href}>{item.name}</Link>
            </li>
          ))}
        </ol>
      </nav>
    </>
  );
}

AI Crawler Handling

AI爬虫处理

Known AI Crawlers

已知AI爬虫

BotUser AgentPurpose
GPTBot
GPTBot
ChatGPT web browsing
ChatGPT-User
ChatGPT-User
ChatGPT user browsing
ClaudeBot
ClaudeBot
Claude web access
Claude-Web
Claude-Web
Claude web features
PerplexityBot
PerplexityBot
Perplexity search
Google-Extended
Google-Extended
Gemini/Bard training
Amazonbot
Amazonbot
Alexa/Amazon AI
CCBot
CCBot
Common Crawl (AI training)
爬虫用户代理用途
GPTBot
GPTBot
ChatGPT网页浏览
ChatGPT-User
ChatGPT-User
ChatGPT用户浏览
ClaudeBot
ClaudeBot
Claude网页访问
Claude-Web
Claude-Web
Claude网页功能
PerplexityBot
PerplexityBot
Perplexity搜索
Google-Extended
Google-Extended
Gemini/Bard训练
Amazonbot
Amazonbot
Alexa/亚马逊AI
CCBot
CCBot
Common Crawl(AI训练数据集)

Allow AI Discovery, Block Training (Optional)

允许AI发现,阻止训练(可选)

txt
undefined
txt
undefined

robots.txt

robots.txt

Allow GPTBot for ChatGPT browsing

允许GPTBot用于ChatGPT浏览

User-agent: GPTBot Allow: /
User-agent: GPTBot Allow: /

Block CCBot (used for training datasets)

阻止CCBot(用于训练数据集)

User-agent: CCBot Disallow: /
User-agent: CCBot Disallow: /

Block Google AI training, allow search

阻止谷歌AI训练,允许搜索

User-agent: Google-Extended Disallow: /
undefined
User-agent: Google-Extended Disallow: /
undefined

AI-Specific Meta Tags

AI专属元标签

html
<!-- Block AI training but allow indexing -->
<meta name="robots" content="index, follow, max-image-preview:large">

<!-- Opt out of AI training (proposed standard) -->
<meta name="ai-training" content="disallow">

html
<!-- 阻止AI训练但允许索引 -->
<meta name="robots" content="index, follow, max-image-preview:large">

<!-- 选择退出AI训练(提议中的标准) -->
<meta name="ai-training" content="disallow">

Structured Data Placement

结构化数据放置

Where to Add Schema

Schema添加位置

html
<!-- Option 1: In <head> with JSON-LD (recommended) -->
<head>
  <script type="application/ld+json">
    {
      "@context": "https://schema.org",
      "@type": "Organization",
      "name": "Your Company"
    }
  </script>
</head>

<!-- Option 2: Before closing </body> -->
<body>
  <!-- Page content -->
  <script type="application/ld+json">
    { "@context": "https://schema.org", ... }
  </script>
</body>
html
<!-- 选项1:在<head>中使用JSON-LD(推荐) -->
<head>
  <script type="application/ld+json">
    {
      "@context": "https://schema.org",
      "@type": "Organization",
      "name": "Your Company"
    }
  </script>
</head>

<!-- 选项2:在</body>结束前添加 -->
<body>
  <!-- 页面内容 -->
  <script type="application/ld+json">
    { "@context": "https://schema.org", ... }
  </script>
</body>

Multiple Schema Per Page

单页面多Schema

html
<head>
  <!-- Organization (site-wide) -->
  <script type="application/ld+json">
    { "@context": "https://schema.org", "@type": "Organization", ... }
  </script>

  <!-- BreadcrumbList (navigation) -->
  <script type="application/ld+json">
    { "@context": "https://schema.org", "@type": "BreadcrumbList", ... }
  </script>

  <!-- Article (page-specific) -->
  <script type="application/ld+json">
    { "@context": "https://schema.org", "@type": "Article", ... }
  </script>

  <!-- FAQPage (if FAQ section exists) -->
  <script type="application/ld+json">
    { "@context": "https://schema.org", "@type": "FAQPage", ... }
  </script>
</head>

html
<head>
  <!-- 组织信息(全站通用) -->
  <script type="application/ld+json">
    { "@context": "https://schema.org", "@type": "Organization", ... }
  </script>

  <!-- 面包屑列表(导航) -->
  <script type="application/ld+json">
    { "@context": "https://schema.org", "@type": "BreadcrumbList", ... }
  </script>

  <!-- 文章信息(页面专属) -->
  <script type="application/ld+json">
    { "@context": "https://schema.org", "@type": "Article", ... }
  </script>

  <!-- FAQ页面(如果有FAQ区域) -->
  <script type="application/ld+json">
    { "@context": "https://schema.org", "@type": "FAQPage", ... }
  </script>
</head>

Project Structure

项目结构

project/
├── public/
│   ├── robots.txt              # Or generate dynamically
│   ├── sitemap.xml             # Or generate dynamically
│   ├── favicon.ico
│   ├── icon.svg
│   ├── apple-touch-icon.png
│   ├── og-image.jpg            # Default OG image (1200x630)
│   └── manifest.webmanifest
├── app/
│   ├── layout.tsx              # Global metadata
│   ├── robots.ts               # Dynamic robots.txt
│   ├── sitemap.ts              # Dynamic sitemap
│   └── [page]/
│       └── page.tsx            # Page-specific metadata
├── components/
│   ├── SchemaMarkup.tsx
│   ├── Breadcrumbs.tsx
│   └── MetaTags.tsx
└── lib/
    ├── schema.ts               # Schema generators
    └── seo.ts                  # SEO utilities

project/
├── public/
│   ├── robots.txt              # 或动态生成
│   ├── sitemap.xml             # 或动态生成
│   ├── favicon.ico
│   ├── icon.svg
│   ├── apple-touch-icon.png
│   ├── og-image.jpg            # 默认OG图片(1200x630)
│   └── manifest.webmanifest
├── app/
│   ├── layout.tsx              # 全局元数据
│   ├── robots.ts               # 动态生成robots.txt
│   ├── sitemap.ts              # 动态生成站点地图
│   └── [page]/
│       └── page.tsx            # 页面专属元数据
├── components/
│   ├── SchemaMarkup.tsx
│   ├── Breadcrumbs.tsx
│   └── MetaTags.tsx
└── lib/
    ├── schema.ts               # Schema生成器
    └── seo.ts                  # SEO工具函数

Verification & Submission

验证与提交

Search Console Setup

搜索控制台设置

bash
undefined
bash
undefined

Verify ownership methods

所有权验证方式

  1. HTML file upload (google*.html to public/)
  2. Meta tag (add to <head>)
  3. DNS TXT record
  4. Google Analytics (if already installed)
undefined
  1. HTML文件上传(将google*.html放入public/)
  2. 元标签(添加到<head>
  3. DNS TXT记录
  4. Google Analytics(如果已安装)
undefined

Submit Sitemap

提交站点地图

markdown
1. Google Search Console
   - Sitemaps → Add new sitemap → yoursite.com/sitemap.xml

2. Bing Webmaster Tools
   - Sitemaps → Submit sitemap

3. Yandex Webmaster (if relevant)
   - Indexing → Sitemap files

markdown
1. Google Search Console
   - 站点地图 → 添加新站点地图 → yoursite.com/sitemap.xml

2. Bing Webmaster Tools
   - 站点地图 → 提交站点地图

3. Yandex Webmaster(如适用)
   - 索引 → 站点地图文件

Checklist

检查清单

markdown
undefined
markdown
undefined

Technical SEO Checklist

技术SEO检查清单

robots.txt

robots.txt

  • Allow search engines
  • Allow AI bots (GPTBot, ClaudeBot, PerplexityBot)
  • Block admin/private areas
  • Include sitemap reference
  • Test with Google's robots.txt tester
  • 允许搜索引擎访问
  • 允许AI爬虫(GPTBot、ClaudeBot、PerplexityBot)
  • 阻止管理/私有区域
  • 包含站点地图引用
  • 使用Google的robots.txt测试工具验证

Sitemap

站点地图

  • Include all indexable pages
  • Exclude noindex pages
  • Include lastmod dates
  • Submit to Search Console
  • Auto-update on content changes
  • 包含所有可索引页面
  • 排除noindex页面
  • 包含lastmod日期
  • 提交到搜索控制台
  • 内容更新时自动更新

Meta Tags

元标签

  • Unique title per page (50-60 chars)
  • Unique description per page (150-160 chars)
  • Canonical URL on every page
  • Open Graph tags
  • Twitter Card tags
  • 每个页面有唯一标题(50-60字符)
  • 每个页面有唯一描述(150-160字符)
  • 每个页面包含规范链接
  • 配置Open Graph标签
  • 配置Twitter Card标签

URL Structure

URL结构

  • Lowercase, hyphenated
  • Descriptive slugs
  • No query params for content
  • 301 redirects for moved content
  • No broken links
  • 小写、连字符分隔
  • 描述性路径段
  • 内容页面不使用查询参数
  • 为迁移内容设置301重定向
  • 无无效链接

Performance

性能

  • LCP < 2.5s
  • INP < 200ms
  • CLS < 0.1
  • HTTPS enabled
  • Security headers configured
  • LCP < 2.5秒
  • INP < 200毫秒
  • CLS < 0.1
  • 启用HTTPS
  • 配置安全头

Structured Data

结构化数据

  • Organization schema (homepage)
  • BreadcrumbList (all pages)
  • Article schema (blog posts)
  • FAQ schema (FAQ sections)
  • Validate with Rich Results Test

---
  • 首页配置组织Schema
  • 所有页面配置面包屑列表Schema
  • 博客文章配置文章Schema
  • FAQ区域配置FAQ Schema
  • 使用富结果测试工具验证

---

Quick Reference

快速参考

File Checklist

文件检查清单

public/
├── robots.txt          ✓ Required
├── sitemap.xml         ✓ Required
├── favicon.ico         ✓ Required
├── og-image.jpg        ✓ Required (1200x630)
└── manifest.json       ○ Recommended
public/
├── robots.txt          ✓ 必填
├── sitemap.xml         ✓ 必填
├── favicon.ico         ✓ 必填
├── og-image.jpg        ✓ 必填(1200x630)
└── manifest.json       ○ 推荐

Meta Tag Lengths

元标签长度

TagLength
Title50-60 characters
Description150-160 characters
OG Title60-90 characters
OG Description200 characters
Twitter Description200 characters
标签长度
标题50-60字符
描述150-160字符
OG标题60-90字符
OG描述200字符
Twitter描述200字符

Image Sizes

图片尺寸

ImageDimensions
OG Image1200 x 630
Twitter Image1200 x 628
Favicon32 x 32
Apple Touch Icon180 x 180
图片尺寸
OG图片1200 x 630
Twitter图片1200 x 628
网站图标32 x 32
Apple Touch Icon180 x 180