Prerender in the Cloud

blackbing Playground
verybuy-dev
Published in
9 min readJul 31, 2020

隨著 SPA(Single Page Application) 的盛行,越來越多服務用 SPA 來做網站,但 SPA 遇到很大的問題就是 SEO。如果用 SPA 來做動態網站,不用 SSR(Server Side Render) 就很難處理 SEO or Sharing 的問題。但用 SPA 要換成 SSR 的工其實是相對大很多的,而且 SSR 要考慮的事情又多更多,因為既然在 server side,就要針對 server or client 來做不同的邏輯處理,此外又會遇到系統上的問題,像是瞬間流量大,CPU Loading 負擔大等等問題。
#像極了愛情

雖然已經有 next.js 之類的 framework 來協助 SSR 的開發,但針對已經開發好的 SPA 程式,要改成 next.js 也是幾乎需要從頭開始,因此我希望用最小的成本,不要動到網站的核心程式,借由 prerender 來加速我們的網站開發。

本篇文章由 Verybuy 非常勸敗 贊助,Verybuy 非常勸敗 看起來是純電商的一間公司,但 Verybuy 團隊致力於透過技術的力量來解決繁瑣的購物決策與線下流程,只是剛好在透過女性流行商品,提供更多元的女性購物體驗與選擇。

大家好我是 Bingo,專注於前端開發領域,最近對 AWS Lambda 開發很有興趣,談不上專精但希望能拋磚引玉,分享 Lambda 的應用場景與實作。

prerender

prerender 的概念說穿了蠻簡單的,其實就是判斷 user-agent 是否為 crawler ,如果是 crawler 就透過 prerender 給他一個 parsed 過的 html。如果不在意價錢的話,其實直接用 prerender.io 接起來就好。

prerender 流程

但看了一下 prerender.io 的價格,以我們的流量也是會蠻驚人的。因為之前有用 puppeteer 寫過爬蟲之類的程式,覺得蠻簡單的,所以就先來 survey 一下要自己搞 prerender 有哪些工具。

  1. https://render-tron.appspot.com/
  2. https://github.com/puppeteer/puppeteer

問題是我將網站放到 s3 上 host,為了 prerender 這件事情又要再開 server ,開 server 也要錢,遇到量大還要 auto scaling,我覺得很不划算。

Prerender Lambda

AWS Lambda

chrome-aws-lambda 提供了在 AWS Lambda 執行 chrome 的方法,將程式放到 Lambda layer 來執行,這部分照著文件做就可以了。

範例程式看起來很簡單:

const chromium = require('chrome-aws-lambda');exports.handler = async (event, context, callback) => {
let result = null;
let browser = null;
try {
browser = await chromium.puppeteer.launch({
args: chromium.args,
defaultViewport: chromium.defaultViewport,
executablePath: await chromium.executablePath,
headless: chromium.headless,
ignoreHTTPSErrors: true,
});
let page = await browser.newPage(); await page.goto(event.url || 'https://example.com'); result = await page.title();
} catch (error) {
return callback(error);
} finally {
if (browser !== null) {
await browser.close();
}
}
return callback(null, result);
};

這樣就可以透過 AWS Lambda 來執行網站 render 完的結果了。

記得要透過 API Gateway 將 Lambda 接起來,這樣才有辦法被 trigger 。

Prerender Lambda@edge

其實本篇文章的重點現在才要開始。要區分 user-agent 是否為機器人,最簡單的作法是架一台 nginx ,但這樣一來還是需要開 server 來 host nginx。

還好 AWS 提供了 Lambda@edge 來讓開發者可以在 CloudFront 做出更細膩的處理。

不過在了解 Lambda@edge 之前,我們需要理解 CloudFront 的幾個節點在做什麼。

Lambda@edge
  1. Viewer Request: User 發出 request 之後,到 Cloud Front 之前。
  2. Origin Request: 若 Cloud Front 沒有 cache 再向 Origin Server 發出 Request 之前。
  3. Origin Response: 收到 Origin Server 的 response 之後,回應給 Cloud Front 之前。
  4. Viewer Response: 在 Cloud Front 存完 cache 之後,回應給 User 之前。

Lambda@edge 其實就是在這幾個節點之中插入 Lambda function,讓 Cloud Front 可以做更細膩的處理。因此我們在這幾個節點加快 cache 的處理,或是觸發其他 Lambda function 等等。

官方範例

在找資料的過程發現其實官方就有給了一個類似應用場景的架構圖,我看到覺得畫的超清楚的,有興趣的同學可以再點進去閱讀。

Dynamically Route Viewer Requests to Any Origin Using Lambda@Edge

“Talk is cheap, Show me the code!!”

講了這麼多,我們來看看實際一點的程式,要讓 Lambda@edge 動起來,首先要加入這幾個 Lambda Function。

viewer-request:

這個節點的重點在於將 crawler 的 user-agent 區分開來,增加 Cloud Front 的 cache hit-rate。

Origin-Request:

這邊的重點在於記下目前要做 prerender 的 url,塞到 header 裡頭。

Origin-Response:

這個節點的重點是最重要的部分,從 header 拿到需要 prerender 的 url 並發出 prerender 的 request ,拿到 response 回來之後再往後傳。

Cloud Front 設定

最後就是將 Lambda@edge 的程式連接到 Cloud Front 了,這個步驟可以參考 https://github.com/mikaelvesavuori/lambda-dynamic-prerenderer#link-all-lambda-function-associations-and-whitelist-headers,在開發中這份文件幫助了我很多,不過這份文件中蠻多多餘的步驟,所以我並沒有完全參考他的步驟。

mikaelvesavuori/lambda-dynamic-prerenderer

總結

如果你的網站應用程式可以用靜態檔案來 host,而且時間資源有限,無法用 SSR(next.js/nuxt.js /Nest) 開發,那就可以透過 prerender + Lambda@edge 來處理 SEO 的問題。我認為這有幾點好處:

  1. 不需要大幅修改程式:要將 SPA 改成 SSR 本來就不是簡單的事情,透過 Lambda@edge 不用重寫應用程式,是除了 SSR 的另外一個選擇。
  2. 保持簡單:少了 server 邏輯處理,相對單純許多。
  3. 便宜:雖然 Lambda 還是要付錢,但比起開 frontend server,還是得處理 auto scaling 等等機制,Lambda 還是便宜了許多。
  4. 不用擔心大流量:如果要走 prerender 的機制,瓶頸其實在大流量的時候會爆炸,就像 chrome 開太多頁也會爆炸一樣,尤其是 render 時瞬間吃掉的 CPU 非常可怕(如果你有實作過就知道有多可怕)。(當然如果你有 API request 還是得處理大流量,但這是另外的問題)

我認為用 Lambda 來開發應用程式會是將來的趨勢,之前覺得在開發上還是有些不太便利,但隨著工具的進步,現在也可以在 local 開發與 Debug,而且他竟然已經支援這麼多語言了。

如果你對本篇文章的贊助商 Verybuy 非常勸敗 的職缺有興趣的話,可以到 這裡 看看有興趣的職缺。

如果你對如何開發 Lambda 有興趣的話,請給我幾個拍手,我會再分享如何開發 Lambda 應用程式,上傳,打包,Debug 等等開發細節。也歡迎提出討論,訂閱,分享,開啟小鈴鐺。

--

--

blackbing Playground
verybuy-dev

Bingo Yang。記錄一些生活與工作的雜事,偶爾會寫一些前端網頁開發的心得,過去的足跡在 http://blog.blackbing.net