SPA項目開箱即用的SEO解決方案

前言

本文章寫於 2019-07-05 請注意時效性。html

有關 SPA 項目的 SEO 友好的解決方案其實很少, 常見的解決手段以下:前端

  1. 將 SPA 項目改成 SSR 渲染
  2. 使用預渲染

前者很是穩定可是對於已有的 SPA 項目進行改造須要注意的問題有不少並且耗時長與重寫一個沒有太大區別,後者只能對於那些"不管是哪一種用戶訪問返回的結果都同樣"的頁面合適難免十分被動。vue

總的來講都是十分的繁瑣,不過依然有能夠避開修改原有代碼的解決方案, 例以下面的這個:nginx

https://www.cnblogs.com/lipte...

這些方案的基本原理就是,使用代理服務器區分搜索引擎的爬蟲和普通用戶從而實現針對性內容響應,普通用戶響應原有的 SPA 項目也就是「純粹的 index.html 頁面」,而對於爬蟲響應對應路由下的渲染好的HTML頁面。
圖片描述
既然各位智慧無窮的網友開出了藥方,看來咱們須要手動熬製了。不過先慢着看看 github 有什麼現成的藥沒有:
圖片描述
沒錯 github 上已經有了現成的解決方案。git

Rendora 簡介

Rendora 自己是一個代理服務器使用 GO 語言編寫專門被設計與解決 SPA 項目的 SEO 處理,支持配置文件以及對外接口。github

使用 Rendora 能夠相較於其餘方案有以下的優點:redis

  1. 無需修改原有項目
  2. 無需修改構建配置
  3. 支持任意路由頁面的渲染
  4. 不受限於前端框架與所使用到的技術
  5. 搜索引擎爬蟲和普通用戶獲取到的數據一致

它的基本原理就是請求通過 Rendora 的時候它會根據請求頭 user-agent 來判斷請求是屬於爬蟲仍是普通用戶, 普通用戶直接代理到原有的Web服務器, 而爬蟲的請求會通過無頭瀏覽器(head-less browser) 處理生成一張頁面返回給爬蟲,而這個頁面的內容能夠理解爲是運行時的 DOM 快照。chrome

圖片描述

明白了基本原理後咱們不難想到只要是異步加載數據而後再利用數據渲染內容的頁面都適用。並且爬蟲和普通用戶二者最終獲取到的數據能夠高度一致。vue-cli

安裝

Rendora 官方文檔中已經給出了安裝方式,我就在這裏直接照搬了,不過 Rendora 自己是由 GO 語言編寫,並且依賴了無頭瀏覽器仍是有許多小坑要踩的。docker

在本文中我使用的系統是 Ubuntu18.04桌面版 ,可是其餘的系統用戶 windows 和 macos 都是能夠安裝以及使用的,安裝 Rendora 方式稍有不一樣可是基本概念都是一致的。

基本依賴

  1. 須要安裝 Golang 1.11或者更高的版本
  2. 須要安裝 chromium 瀏覽器或者 google-chrome 瀏覽器,要確保能夠在環境變量中能夠訪問到他們

安裝 Rendora

項目地址

安裝方式:

git clone https://github.com/rendora/rendora
cd rendora
make build
sudo make install

另外你還可以使用使用 docker:

docker run --net=host -v ./CONFIG_FILE.yaml:/etc/rendora/config.yaml rendora/rendora

注意: make build 過程當中會訪問網絡, 其中有些地址沒法在國內訪問這會致使構建失敗, 國內用戶沒有開啓代理的能夠嘗試在構建執行以下兩條命令進行代理:

# 啓動 go modules 特性
export GO111MODULE=on
# 設置 GOPROXY 爲環境變量
export GOPROXY=https://goproxy.io

一樣的其餘平臺的能夠參考 goproxy.io 的官方指導.

編寫配置文件

Rendora 是基於配置文件運行的, 在運行前咱們須要熟悉一下配置文件.

配置手冊

配置文件支持多種格式, 這裏我就使用 Web 端最多見的 JSON 格式, 須要注意 Rendora 不會檢查拼寫錯誤, 請多多複製.

默認狀況下咱們只須要指定2個參數就能夠了:

{
    "backend": {
        "url": "http://127.0.0.1:8000"
    },
    "target": {
        "url": "http://127.0.0.1"
    }
}
參數 含義
backend 原來向用戶提供服務的地址
target 無頭瀏覽器請求的地址

請注意: 由於 Rendora 本質上是一個代理服務器也會啓動端口監聽(默認3001端口), 這兩個參數具體填寫的內容取決於後端技術的組合, 例如一個常見的技術組合多是下面這個樣子:

nginx->Rendora->App Server

但也有多是反過來的:

Rendora->nginx->App Server

例如: 我在本地的服務器上監聽了80端口用於託管項目的靜態文件, 那麼實際上這兩個參數的配置是同樣的, 由於原有的地址和瀏覽器請求的地址是一致的.

此外爲了不和本地的端口衝突這裏還有兩個選項是須要注意的:

{
  "listen":{
    "port":3001
  },
  "headless":{
    "internal":{
      "url":"http://localhost:9222"
    },
  },
}
  • listen.port 指的是 Rendora 監聽的端口號
  • headless.internal.url 指的是無頭瀏覽器的請求的地址

此外 Rendora 還能夠配置兩種過濾器:

  1. 請求過濾器 - 決定哪些請求是通過無頭瀏覽器渲染後的, 哪些請求被轉發
  2. 路徑過濾器 - 只有符合請求請求過濾器的請求才會通過路由過濾器, 只有符合路徑過濾過濾器規則的請求才會容許經過.

一個常見的請求過濾器例子以下:

注意:不要複製註釋

---
  "filters":{ // 請求過濾器 經過過濾的使用無頭瀏覽器渲染
    "userAgent":{
      "defaultPolicy":"blacklist", // 匹配策略 黑名單模式(默認全部請求沒法經過過濾器)
      "exceptions":{ // 只有符合下列規則的請求才會經過過濾
          // 只要 user-agent 中含有下列字符之一就符合匹配條件
        "keywords":["bot", "bing", "yandex", "slurp", "duckduckgo","baiduspider","googlebot","360spider","Sosospider","sogou spider"]
      },
      // user-agent 徹底匹配下方內容的也能夠經過
      "exact":["Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.67 Safari/537.36"]
    }
  }
---

加上地址過濾器:

---
"paths":{ // 路徑過濾器 符合規則的纔會被無頭瀏覽器渲染
      "defaultPolicy": "whitelist", // 白名單模式 全部的請求默認都會經過過濾器
      "exceptions":{ // 除了符合下列規則的會被無視
        "prefix":["/home"], // 前綴匹配
        "exact":["/hello/world"] // 完整匹配
      }
    }
---

關鍵參數 headless.waitAfterDOMLoad:

一個 SPA 項目中的 DOMLoad 事件觸發並不意味着頁面渲染完成, 由於網絡請求還未完成內容還未渲染到實際的 DOM 中.

而 Rendora 默認狀況下 DOMLoad 後就輸出 DOM 快照的, 因此咱們須要手動指定一個 DOMLoad 完成後的延時時間, 到了這個時間後纔會獲取快照.

不一樣項目的初次加載完成不一樣, 具體延時多少毫秒可使用 chrome 的 network 面板測量, 這裏我使用了延時2秒也就是2000毫秒, 這個配置能夠在下方的完整例子中找到.

另外 Rendora 還會忽略掉幾乎所有的資源文件的加載(可配置請參考文檔)實際狀況中會比用戶瀏覽器的加載速度快一些.

完整的例子:

{
  "listen":{
    "port":3001
  },
  "target":{
    "url":"http://localhost:8080"
  },
  "backend":{
    "url":"http://localhost:8080"
  },
  "headless":{
    "internal":{
      "url":"http://localhost:9222"
    },
    "waitAfterDOMLoad":2000
  },
  "filters":{
    "userAgent":{
      "defaultPolicy":"blacklist",
      "exceptions":{
        "keywords":["bot", "bing", "yandex", "slurp", "duckduckgo","baiduspider","googlebot","360spider","Sosospider","sogou spider"]
      },
      "exact":["Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.67 Safari/537.36"]
    },
    "paths":{
      "defaultPolicy": "whitelist",
      "exceptions":{ 
        "prefix":["/about"], 
        "exact":["/active/123"]
      }
    }
  }
}

運行

啓動無頭瀏覽器

咱們使用剛纔的配置進行運行, 首先啓動無頭瀏覽器:

# chromium 版本
chromium-browser --headless --disable-gpu --remote-debugging-port=9222
# google-chrome 版本
google-chrome --headless --disable-gpu --remote-debugging-port=9222

啓動項目

而後啓動咱們的項目, 這裏我使用 vue-cli3 建立了一個默認的項目而且以開發模式啓動,該項目監聽了8080端口:

npm run serve

圖片:瀏覽器中表現
圖片描述

啓動 Rendora

rendora --config ./config.json

測試

先使用 postman 進行無 header 請求一次而後查看 / 路徑下返回的具體內容, 注意咱們這裏請求的是 Rendora 開啓的 3001 端口而不是項目的 8080 端口.

圖片: 沒有使用 header 請求的結果:
圖片描述
從圖片中能夠看到頁面尚未任何渲染結果.

此次請求的時候添加上 user-agent header 而且查看輸出結果.

圖片: 添加 header 後的輸出:
圖片描述
此時能夠明顯感受到響應有延時, 隨後輸出了頁面的內容, 不過這種延時不是一直存在的 Rendora 會對該地址下的內容進行緩存隨後的訪問中講不會進行任何渲染,而且你能夠指定緩存時間, 另外你還能夠將緩存移動到 redis 中進行管理.

咱們還能夠嘗試被配置中被禁止訪問的 /about:
圖片描述
此時能夠看到被攔截的 /about 地址返回的是 index.html 中的內容而不是渲染好的 about 頁面。

相關內容 & 參考

http://www.runtester.com/deta...
https://github.com/rendora/re...
https://github.com/rendora/re...
相關文章
相關標籤/搜索