搜尋抓取

單頁應用的前端路由:URL 發現不能只靠脚本渲染

單頁應用的 URL 常常藏在脚本渲染之後,搜尋蜘蛛能不能發現,取决于首屏是否留下可爬出口。本文對比纯客戶端渲染、服務端渲染與 Sitemap 兜底三種入口形態的差异,整理 hash 路由、直達 404、点击事件代替連結、路由懒加载等常见盲区,並给出一套從關閉脚本到日誌核對的检查顺序。

搜尋抓取

單頁應用的前端路由:URL 發現不能只靠脚本渲染

為什么前端路由會成為 URL 發現的盲区

多頁站点的連結通常直接寫在 HTML 源碼里,搜尋蜘蛛拿到文档就能顺着锚点繼續走。單頁應用不一样:首屏返回的 HTML 往往只是一個空壳容器,導航、列表、正文連結都是浏览器执行脚本之後才出現的。蜘蛛能不能拿到這些連結,取决于它有没有执行脚本、执行到哪一步、以及首屏是否留下了不依赖脚本的出口。

換句话说,URL 發現這件事,在前端路由结构里被從服務端搬到了客戶端。鏈路變長,断点自然也變多。

三種常见的入口形態及其局限

纯客戶端渲染

路由跳轉靠 history API 或井号路由,連結节点由脚本生成。這類结构里,URL 的發現高度依赖渲染過程。風險在于:渲染超时、接口报错、脚本被拦截,都會让頁面變成一個没有出口的死胡同——用戶能点,蜘蛛走不動。

服務端渲染或预渲染

首屏带完整連結,抓取路径接近传统站点,是目前對發現相對友好的做法。需要注意的是,渲染层輸出的連結要與源站實际存在的路径一致;如果渲染缓存過期或路由表與後端路径脱节,就可能出現“頁面里有的連結,打開是 404”的情况。

Sitemap 與静態列表兜底

不管前端怎么渲染,Sitemap、RSS、分類頁的静態化列表都是不执行脚本也能讀到的發現通道。它們不一定提升抓取频次,但能保證 URL 至少有一個不依赖渲染的入口。前提是里面的路径要定期與线上實际路径核對,別让兜底本身成為過期清單。

几個容易忽略的细节

  • 井号路由:井号後面的部分通常不會被当成獨立 URL,同一路径可能只算一個頁面。要做索引的路径,尽量用 history 模式。
  • 直達連結返回 404:history 模式下,從外部直接打開深层路径时,服務器若没有配置回退到入口文件,會返回 404。蜘蛛拿到 404 就不會繼續往下走。
  • 点击事件代替連結:用可点击的容器加脚本跳轉,人能用,但没有可提取的地址。能寫成原生連結的位置,就寫原生連結。
  • 路由懒加载:首屏只加载目前頁面,其他路由的入口要么出現在導航里,要么就完全没暴露。導航、面包屑、相關推荐這些位置,最好保留真實連結。
  • 渲染接口被挡:渲染依赖的資料接口若對蜘蛛請求返回空或报错,渲染出来的仍是一個空頁面,連結同样拿不到。

一套可以照着走的自检顺序

  1. 關閉浏览器脚本,打開首頁和分類頁,數一數首屏還剩多少個可以点的連結。
  2. 查看源碼而不是渲染後的 DOM,確認連結是否出現在服務器返回的 HTML 里。
  3. 從日誌里挑几個訪問次數很少或從未出現的深层路径,手動直達,確認返回狀態碼與首屏内容正常。
  4. 核對 Sitemap 中的路径與前端路由表能否一一對應,避免出現只存在于路由表、却不在任何入口中的頁面。
  5. 確認服務器的回退規則:任意深层路径直達都返回 200 且带首屏内容,而不是 404 或空白壳。

把入口做成冗余,而不是單点

前端路由本身没有問题,問题在于把發現的责任全压在渲染上。實际运营中比較稳的搭配是:導航和列表保持真實連結,Sitemap 覆盖全量路径,服務器保證直達可用。三件事各管一段,任何一段出問题,URL 都還有別的路可以進来。

發現路径可以被前端改造,但不该只依赖前端。让不执行脚本的通道也能走通,是單頁站点最實际的兜底。