了解 JavaScript SEO 基础知识

JavaScript 是网络平台的重要组成部分,因为它提供的很多功能可将网络转变成一个非常强大的应用平台。请设法让用户能够通过 Google 搜索轻松找到您的由 JavaScript 提供支持的 Web 应用,这样做有助于您在用户搜索您的 Web 应用所提供的内容时发掘新用户并再度吸引现有用户。虽然 Google 搜索使用常青 Chromium 来运行 JavaScript,但您可从几个方面进行优化

本指南将介绍 Google 搜索如何处理 JavaScript,以及与针对 Google 搜索改进 JavaScript Web 应用相关的最佳实践。

Google 如何处理 JavaScript

Google 对 JavaScript 网络应用的处理流程分为 3 大阶段:

  1. 抓取
  2. 呈现
  3. 索引编制

Googlebot 从抓取队列中获取网址,对其进行抓取,然后将其传递到处理阶段。在处理阶段,Googlebot 会提取重新回到抓取队列的链接,并将网页加入渲染队列。网页从渲染队列进入渲染程序,渲染程序将所渲染的 HTML 传递回处理阶段,从而将内容编入索引并提取链接以将其放入抓取队列中。

Googlebot 会将网页加入队列以进行抓取和呈现。当某个网页正在等待被抓取/被渲染时,这种状态很难直接判断出来。

当 Googlebot 尝试通过发出 HTTP 请求从抓取队列中抓取某个网址时,它首先会检查您是否允许抓取。Googlebot 会读取 robots.txt 文件。如果此文件将该网址标记为“disallowed”,Googlebot 就会跳过向该网址发出 HTTP 请求的操作,然后会跳过该网址。

接下来,Googlebot 会解析 HTML 链接的 href 属性中其他网址的响应,并将这些网址添加到抓取队列中。若不想让 Googlebot 发现链接,请使用 nofollow 机制

抓取网址并解析 HTML 响应非常适用于传统网站或服务器端渲染的网页;在这些网站或网页中,HTTP 响应中的 HTML 包含所有内容。某些 JavaScript 网站可能会使用应用 Shell 模型;在该模型中,初始 HTML 不包含实际内容,并且 Google 需要执行 JavaScript,然后才能查看 JavaScript 生成的实际网页内容。

Googlebot 会将所有网页都加入渲染队列,除非 robots meta 标记或标头告知 Google 不要将网页编入索引。网页在此队列中的存在时长可能会是几秒钟,但也可能会是更长时间。一旦 Google 的资源允许,无头 Chromium 便会渲染相应网页并执行 JavaScript。Googlebot 会再次解析所渲染的链接 HTML,并将找到的网址加入抓取队列。Google 还会使用所呈现的 HTML 将网页编入索引。

请注意,依然建议您采取服务器端渲染或预渲染,因为:(1) 它可让用户和抓取工具更快速地看到您的网站内容;(2) 并非所有漫游器都能运行 JavaScript。

用独特的标题和摘要来描述网页

独特的描述性 <title> 元素和有用的元描述可帮助用户快速找到符合其目标的最佳结果;我们的指南中解释了怎样才算是良好的 <title> 元素元描述

您可以使用 JavaScript 设置或更改元描述及 <title> 元素。

Google 搜索可能会根据用户的查询显示不同的标题链接。 当标题或描述与网页内容的相关度较低时,或者当我们在网页中找到了与搜索查询更相符的替代项时,就会发生这种情况。详细了解为什么搜索结果标题可能与网页的 <title> 元素不同

编写兼容的代码

浏览器提供了很多 API,而 JavaScript 是一种快速演变的语言。Google 对所支持的 API 和 JavaScript 功能有一些限制。若要确保您的代码与 Google 兼容,请遵循我们的 JavaScript 问题排查指南

如果您使用功能检测机制检测到您所需的某个浏览器 API 缺失了,我们建议您使用差异化渲染和 polyfill。由于无法对一些浏览器功能使用 polyfill,因此我们建议您查看 polyfill 文档以了解是否存在某些限制条件。

使用有意义的 HTTP 状态代码

Googlebot 会通过 HTTP 状态代码确定抓取网页时是否出现了问题。

如需告知 Googlebot 无法抓取某个网页或无法将某个网页编入索引,请使用有意义的状态代码(例如:404 表示找不到网页,401 代码表示必须登录才能访问网页)。您可以使用 HTTP 状态代码告知 Googlebot 某个网页是否已移至新网址,以便系统相应地更新索引。

这里列出了 HTTP 状态代码及其对 Google 搜索的影响。

避免单页应用中出现 soft 404 错误

在客户端呈现的单页应用中,路由通常实现为客户端路由。 在这种情况下,使用有意义的 HTTP 状态代码可能是无法实现或不实际的。 为避免在使用客户端渲染和路由时出现 soft 404 错误,请采用以下策略之一:

  • 使用 JavaScript 重定向至服务器响应 404 HTTP 状态代码(例如 /not-found)的网址。
  • 使用 JavaScript 向错误页面添加 <meta name="robots" content="noindex">

以下是重定向方法的示例代码:

fetch(`/api/products/${productId}`)
.then(response => response.json())
.then(product => {
  if(product.exists) {
    showProductDetails(product); // shows the product information on the page
  } else {
    // this product does not exist, so this is an error page.
    window.location.href = '/not-found'; // redirect to 404 page on the server.
  }
})

以下是 noindex 标记方法的示例代码:

fetch(`/api/products/${productId}`)
.then(response => response.json())
.then(product => {
  if(product.exists) {
    showProductDetails(product); // shows the product information on the page
  } else {
    // this product does not exist, so this is an error page.
    // Note: This example assumes there is no other robots meta tag present in the HTML.
    const metaRobots = document.createElement('meta');
    metaRobots.name = 'robots';
    metaRobots.content = 'noindex';
    document.head.appendChild(metaRobots);
  }
})

使用 History API 而非片段

只有当链接是包含 href 属性的 <a> HTML 元素时,Google 才能抓取您的链接。

对于实现客户端路由的单页应用,请使用 History API 在 Web 应用的不同视图之间实现路由。为确保 Googlebot 能够解析并抓取您的网址,请避免使用片段加载不同的网页内容。以下示例是一个不好的做法,因为 Googlebot 无法可靠地解析网址:

<nav>
  <ul>
    <li><a href="#/products">Our products</a></li>
    <li><a href="#/services">Our services</a></li>
  </ul>
</nav>

<h1>Welcome to example.com!</h1>
<div id="placeholder">
  <p>Learn more about <a href="#/products">our products</a> and <a href="#/services">our services</p>
</div>
<script>
window.addEventListener('hashchange', function goToPage() {
  // this function loads different content based on the current URL fragment
  const pageToLoad = window.location.hash.slice(1); // URL fragment
  document.getElementById('placeholder').innerHTML = load(pageToLoad);
});
</script>

不过,您可以通过实现 History API,确保 Googlebot 可以访问您的网址:

<nav>
  <ul>
    <li><a href="/products">Our products</a></li>
    <li><a href="/services">Our services</a></li>
  </ul>
</nav>

<h1>Welcome to example.com!</h1>
<div id="placeholder">
  <p>Learn more about <a href="/products">our products</a> and <a href="/services">our services</p>
</div>
<script>
function goToPage(event) {
  event.preventDefault(); // stop the browser from navigating to the destination URL.
  const hrefUrl = event.target.getAttribute('href');
  const pageToLoad = hrefUrl.slice(1); // remove the leading slash
  document.getElementById('placeholder').innerHTML = load(pageToLoad);
  window.history.pushState({}, window.title, hrefUrl) // Update URL as well as browser history.
}

// Enable client-side routing for all links on the page
document.querySelectorAll('a').forEach(link => link.addEventListener('click', goToPage));

</script>

您可以使用 JavaScript 注入 rel="canonical" 链接标记,但我们不建议这样做。 在呈现网页时,Google 搜索会提取注入的规范网址。 下例展示了如何使用 JavaScript 注入 rel="canonical" 链接标记:

fetch('/api/cats/' + id)
  .then(function (response) { return response.json(); })
  .then(function (cat) {
    // creates a canonical link tag and dynamically builds the URL
    // e.g. https://example.com/cats/simba
    const linkTag = document.createElement('link');
    linkTag.setAttribute('rel', 'canonical');
    linkTag.href = 'https://example.com/cats/' + cat.urlFriendlyName;
    document.head.appendChild(linkTag);
  });

谨慎使用 robots meta 标记

您可以通过 robots meta 标记阻止 Google 将某个网页编入索引或跟踪链接。 例如,在网页顶部添加以下 meta 标记可阻止 Google 将该网页编入索引:

<!-- Google won't index this page or follow links on this page -->
<meta name="robots" content="noindex, nofollow">

您可以使用 JavaScript 将 robots meta 标记添加到网页中或更改其内容。以下示例代码展示了如何使用 JavaScript 更改 robots meta 标记以防止在 API 调用未返回内容时将当前网页编入索引。

fetch('/api/products/' + productId)
  .then(function (response) { return response.json(); })
  .then(function (apiResponse) {
    if (apiResponse.isError) {
      // get the robots meta tag
      var metaRobots = document.querySelector('meta[name="robots"]');
      // if there was no robots meta tag, add one
      if (!metaRobots) {
        metaRobots = document.createElement('meta');
        metaRobots.setAttribute('name', 'robots');
        document.head.appendChild(metaRobots);
      }
      // tell Google to exclude this page from the index
      metaRobots.setAttribute('content', 'noindex');
      // display an error message to the user
      errorMsg.textContent = 'This product is no longer available';
      return;
    }
    // display product information
    // ...
  });

Google 在运行 JavaScript 之前,如果在 robots meta 标记中遇到 noindex,便不会渲染相应网页,也不会将其编入索引。

使用长效缓存

Googlebot 会主动缓存内容,以减少网络请求和资源使用量。WRS 可能会忽略缓存标头。这可能会导致 WRS 使用过时的 JavaScript 或 CSS 资源。为了避免这个问题,您可以创建内容指纹,使其成为文件名的一部分(如 main.2bb85551.js)。指纹取决于文件的内容,因此每次更新都会生成不同的文件名。如需了解详情,请参阅 web.dev 长效缓存策略指南

使用结构化数据

在您的网页上使用结构化数据时,您可以使用 JavaScript 生成所需的 JSON-LD 并将其注入网页中。请务必测试您的实现效果,避免出现问题。

遵循网络组件最佳做法

Google 支持网络组件。 当 Google 呈现某个网页时,它会扁平化 shadow DOM 和 light DOM 内容。 这意味着 Google 只能看到在所呈现的 HTML 中可见的内容。若要确保 Google 在您的内容渲染后仍能看到该内容,请使用富媒体搜索结果测试网址检查工具并查看所渲染的 HTML。

如果该内容在所呈现的 HTML 中不可见,Google 将无法将其编入索引。

以下示例会创建一个网络组件,以便在其 shadow DOM 内显示 light DOM 内容。 确保 light DOM 和 shadow DOM 内容均能显示在所呈现的 HTML 中的一种方法是使用 Slot 元素。

<script>
  class MyComponent extends HTMLElement {
    constructor() {
      super();
      this.attachShadow({ mode: 'open' });
    }

    connectedCallback() {
      let p = document.createElement('p');
      p.innerHTML = 'Hello World, this is shadow DOM content. Here comes the light DOM: <slot></slot>';
      this.shadowRoot.appendChild(p);
    }
  }

  window.customElements.define('my-component', MyComponent);
</script>

<my-component>
  <p>This is light DOM content. It's projected into the shadow DOM.</p>
  <p>WRS renders this content as well as the shadow DOM content.</p>
</my-component>

呈现后,Google 可以将此内容编入索引:

<my-component>
  Hello World, this is shadow DOM content. Here comes the light DOM:
  <p>This is light DOM content. It's projected into the shadow DOM<p>
  <p>WRS renders this content as well as the shadow DOM content.</p>
</my-component>
    

修正图片和延迟加载的内容

图片在带宽和性能方面的开销可能会非常高昂。一种可取的策略是:使用延迟加载方法,仅在用户即将看到图片时才加载图片。若要确保以方便用户搜索的方式实现延迟加载,请遵循我们的延迟加载指南

以无障碍为设计宗旨

针对用户(而不仅仅针对搜索引擎)创建网页。在设计网站时要考虑用户的需求,包括那些可能使用不支持 JavaScript 功能的浏览器的用户(例如使用屏幕阅读器或旧版移动设备的用户)。测试网站可访问性的其中一种最简单的方法是:在停用 JavaScript 后通过浏览器预览网站,或在纯文本浏览器(例如 Lynx)中查看网站。以纯文本形式查看网站还可帮助您找出 Google 难以看到的其他内容,例如图片中嵌入的文字。