
語言 🇹🇼 繁體中文
Val Town 安裝
投票
為 Val Town 應用程式新增即時評論功能
Val Town 在 Deno 上執行 TypeScript,因此 val 是一個真實的伺服器。這使它非常適合 FastComments:小工具是頁面上的 script 標籤,任何需要機密的功能,如 Secure SSO 或驗證 webhook,都可以在同一個 val 的伺服器端執行。
本指南說明如何將評論小工具加入 HTTP val、在索引頁面顯示評論計數、使用他們已擁有的 Val Town 帳號登入使用者,以及接收評論 webhook。
您不需要帳號即可試用。範例使用 tenantId: "demo",這是一個共享的 sandbox,第二步說明如何切換到您自己的環境。
步驟 1:新增小工具 
小工具是一個 script 標籤和一個容器元素,因此可以直接放入你的 val 已經渲染的內容中。此範例使用 Hono JSX,這正是 Val Town 的 HTTP 範本所使用的技術。
Run 
在上線前先決定 urlId
urlId 決定留言會落在哪個討論串中。若不設定,它會預設為目前頁面 URL 經過清理後的版本,而這正是 Val Town 上會變動的部分:在你認領子網域之前,val 會有一個很長的 *.web.val.run 主機名稱、分支會有各自的 URL,而重新命名頁面則會改變路徑。每一種變化都會默默變成一個獨立且空白的討論串,症狀看起來就像「我的留言消失了」。
請將它設定為你可控的穩定值,例如文章的 slug 或資料庫 id,如上例所示。同時也傳入 url,這樣通知郵件與審核工具才能連回實際頁面。
在沒有 JavaScript 的情況下保留留言
FastComments 會在伺服器端渲染完整的討論串,val 可以將其放入 <noscript> 區塊中:
Run 
請對參數進行 URL 編碼。伺服器端版本支援匿名與登入留言、SSO 以及巢狀回覆。
步驟 2:使用您自己的帳戶 
tenantId: "demo" 是一個共享的公共沙盒。它無需註冊即可運作,這也是範例使用它的原因,但其他所有使用 FastComments 的人都會寫入相同的討論串,且任何人都可以對其進行審核。請在發布任何重要內容之前切換。
您的租戶 ID 位於 API 密鑰頁面。
租戶 ID 是公開的,應放在瀏覽器程式碼中。API 密鑰則不應如此,且本頁面不需要任何 API 密鑰。
從環境變數讀取
Val Town 的 vals 在免費層是公開的,因此它們的來源是全世界可讀的。請將任何敏感資訊放在環境變數中,使用 Deno.env.get 讀取:
Run 
這在 Val Town 上尤為重要,原因有二:重新混合一個 val 會複製環境變數的鍵名,但不會複製其值。 放在環境變數中的密鑰不會隨你的 val 進入他人的帳戶。寫入檔案的密鑰則會。
回退到 "demo" 可讓該 val 在任何人在設定自己的租戶之前重新混合時仍能正常運作。
EU 帳戶
一個帳戶、其資料與金鑰都位於同一區域。如果您的帳戶是在 eu.fastcomments.com 建立的,則每個小工具設定也需要 region: "eu",且腳本會從 cdn-eu.fastcomments.com 載入。否則請保持兩者不變。
索引頁面的評論計數 
在索引頁面上,不要為每一列渲染單一的 comment-count 小部件。這會對每篇文章產生一次請求。請使用批量計數,它只需要對整個頁面發出一次請求。
在每一列上標記其線程使用的 urlId,然後一次性載入批量小部件:
Run 
此腳本會在頁面上尋找所有 .fast-comments-count 元素,並填入相應的計數。
data-fast-comments-url-id 必須與文章評論小部件使用的 urlId 相匹配。如果小部件使用 slug,標記也使用 slug。若不匹配,則即使線程中有評論也會顯示為零。
此腳本會輪詢 window.FastCommentsBulkCountConfig,因此無論您在 script 標籤之前或之後設定配置都沒關係。
使用 std/oauth 進行安全單點登入 
如果您的 val 已經知道訪客是誰,Secure SSO 會將該身份交給小工具,讓他們永遠不會看到第二次登入。無需建立任何端點,也不需要在執行時呼叫任何東西:您在伺服器端計算三個值,並將它們傳入小工具設定中。
Val Town 內建零設定登入功能,使用 std/oauth,因此訪客可以使用他們已有的 Val Town 帳號登入。您可以將其替換為您應用程式使用的任何方式;FastComments 部分則保持不變。
在伺服器上建立 Payload
API 密鑰會對 payload 進行簽名,且絕不能出現在瀏覽器程式碼中。從 npm 安裝 SDK,即可直接在 Val Town 的 Deno 執行環境中使用:
Run 
getPayload() 會回傳 { userDataJSONBase64, verificationHash, timestamp }。這三個值就是傳遞到瀏覽器的全部內容。密鑰會對它們簽名,之後即被丟棄,因此頁面中沒有任何東西可以讓讀者偽造其他使用者。
將其傳入小工具
Run 
oauthMiddleware 會為您新增 GET /auth/login、GET /auth/callback 與 POST /auth/logout。請注意,登出是 POST,而小工具會以 GET 方式導向 logoutURL,因此請將 logoutURL 指向您自行實作的、會送出 POST 的小路由。
當訪客已登出時,僅傳入包含 loginURL 的 sso。小工具隨即顯示登入提示,而非匿名留言框。
常見問題
timestamp 為 epoch 毫秒,不能是未來的時間,也不能超過兩天前。請在伺服器端於計算雜湊的同一個請求中產生它。在瀏覽器端產生是典型的失敗情形:產生的值與雜湊時使用的值不同,導致所有留言皆被拒絕。
千萬不要從身分提供者設定 isAdmin 或 isModerator。使用 Val Town 帳號登入並不代表該使用者應該擔任站點的管理員或版主。
請參閱 SSO guide 以取得完整欄位清單、群組限制的討論串以及徽章資訊。
接收 Webhook 
A val 是一個自然的 webhook 接收器:它具有穩定的 URL、能驗證簽名,且內建 SQLite 與 blob 儲存。
FastComments 使用您帳戶的 API 密鑰對 ${timestamp}.${body} 進行簽名,並傳送兩個標頭:
Run 
此方法攜帶事件:對於新建或更新的評論使用 PUT,對於已刪除的評論使用 DELETE。
Run 
兩個常見的陷阱
驗證原始位元組。 解析 JSON 並重新序列化會改變鍵的順序與空白,導致雜湊不同,所有傳遞都會失敗且沒有明顯原因。這通常是 webhook 接收器「根本無法運作」的原因。
以恆定時間比較。 對簽名使用普通的 === 會洩漏匹配的位元組數量,足以一次偽造一個位元組。
處理事件
快速回應。FastComments 會在非 2xx 回應時重試,且持續失敗的端點最終會自動被停用,因此應在回應後再執行實際工作,而非內嵌於回應中。
使其在評論 ID 上具備冪等性。重試時會使用新的時間戳重新簽名,同一評論 ID 在編輯與刪除時會再次到達,因此沒有穩定的依據可用於去重。
範例 Vals 
四個公開的 val 供您 remix,每個涵蓋本指南的一部分。
Blog with comments(線上版)是一個 Markdown 部落格,每篇文章下方都有留言串,並在索引頁顯示大量留言數。Remix 後立即可用,只需一個環境變數即可指向您自己的帳號。
SSO demo(線上版)會使用訪客的 Val Town 帳號登入,並將該身分傳遞給小工具,因此無需第二次登入。
Webhook receiver(線上版)會驗證每次傳送的 HMAC 簽章,並將事件儲存在 SQLite 中。它提供一個按鈕,可簽署測試酬載並傳送給自己,讓您在設定真實 webhook 之前先看到驗證成功的過程。
Agent skills(線上版)是一個 FastComments agent skills 函式庫,涵蓋小工具、SSO、REST API、審核,以及從 Disqus 遷移。Remix 之後,Val Town 的 agent Townie 會自動從 skills/ 目錄取得這些 skills,因此您的 agent 無需您將文件貼到聊天中,就知道如何設定留言功能。
同樣的 skills 也可以在其他地方使用 npx skills add fastcomments/skills 安裝。
網域錯誤 
一旦關閉 demo 租戶,元件可能會因授權錯誤而無法載入。這是因為 FastComments 不知道它應該允許您的帳戶在該域名上使用。
Val Town 值得再看一次,因為一個 val 可能可以透過多個主機名稱存取:
- 每個 HTTP val 都有一個較長的預設端點,
<org>--<id>.web.val.run。 - 申請自訂子域名會新增
<name>.val.run。 - 一個自訂域名會再新增一個。
- 分支會有自己的 URL。
將您實際提供元件服務的所有主機名稱都加入。若在設定完成後再申請子域名,也請將其加入,否則元件會在舊的 URL 上運作,而在新的 URL 上失敗。