用 Vue、React 或類似框架搭建的站点,頁面切換靠前端路由完成,用戶点起来很顺,但換到蜘蛛的视角,可能整站只看到一張 HTML。URL 發現的前提是頁面上存在能被点開、能被解析的連結,單頁應用恰好最容易在這個环节掉鏈子。
先分清 hash 模式和 history 模式
前端路由常见的两種寫法,對 URL 發現的影响完全不同。
- hash 模式:地址形如 example.com/#/news/123。井号後面的部分不會作為獨立 URL 向服務器發起請求,蜘蛛即使拿到這個地址,抓到的也只是首頁那份 HTML,後面那段路由信息基本等于没有。
- history 模式:地址形如 example.com/news/123,是真實、可請求的 URL。只要服務器做了回退配置,让未匹配的路径返回應用入口,蜘蛛就能直接拿到頁面。
所以如果内容頁還在用 hash 路由,優先把它改成 history 模式,這是最基础的一步。
首屏 HTML 里有没有連結
換成 history 模式只是让 URL 變真,接下来還要回答一個問题:服務器返回的這份 HTML 里,有没有下一层内容的入口?
不少單頁應用的入口 HTML 只有一個空容器,導航和列表全部由 JS 挂载。蜘蛛虽然越来越能执行 JS,但执行有预算、有超时,指望它把整站渲染一遍並不划算。更稳的做法是让入口 HTML 本身就带連結。
可以這样自查
- 用命令行請求一個栏目頁,看看返回的源碼里有没有指向内容頁的 href。
- 在浏览器里關掉 JavaScript,看看還能不能点到下一层。
- 對照服務端日誌,確認内容頁的 URL 是否被單獨請求過。
判断标准很简單:把 JS 關掉,如果頁面上還能顺着点下去,URL 發現基本就没有大問题。
几種務實的處理方式
服務端渲染或预渲染
對導航、栏目列表這類關键路径做服務端渲染或预渲染,輸出的 HTML 里直接带 a 标簽。改造范围不用铺满全站,先把主干走通即可。
首屏先輸出一批真實連結
列表頁不必等接口返回全部資料再渲染。首屏可以先輸出十几條真實連結,剩下的再用前端路由挂载。
路由懒加载別影响連結本身
按需加载组件没問题,但連結的 href 應该在 HTML 阶段就寫好,而不是点击时才用脚本跳轉。用 click 事件代替 a 标簽,蜘蛛拿不到入口。
用站点地图兜底
服務端渲染成本較高时,至少让 XML 站点地图覆盖全部内容 URL,作為一條獨立的發現通道。它不能替代内鏈,但能保證内容頁不至于完全没人带路。
几個常见坑
- 所有路由都返回 200。不存在的詳情頁也返回應用外壳,等于给蜘蛛递了一堆内容相同的頁面。
- 路由參數被無限拼接。篩選、排序、分頁參數组合出来的 URL 數量可能遠超真實内容。
- 把導航寫死在 JS 數组里。連結存在,但不出現在 HTML 中。
- 只在頁面底部放一個“加载更多”按钮,却不给對應的分頁 URL。
單頁應用不是不能被發現,而是要把“依赖 JS 才存在”的連結,變回“HTML 里就存在”的連結。這一层理顺了,抓取和收錄才有繼續讨论的余地。