上篇《部落格系統知多少:揭秘那些不為人知的學問(一)》介紹了部落格的歷史、我的部落格故事及部落格的受眾來源。本篇精彩繼續,介紹部落格基本功能設計要點。
目錄
由於文章篇幅較長,本文將分為 4 篇推送,目錄如下:
- 「部落格」的前世今生
- 我的部落格故事
- 誰是部落格的受眾?
- 部落格基本功能設計要點
- 4.1 文章(Post)
- 4.2 迴響(Comment)
- 4.3 分類(Category)
- 4.4 標籤(Tag)
- 4.5 封存(Archive)
- 4.6 頁面(Page)
- 4.7 訂閱
- 4.8 版本控制
- 4.9 主題及個人化
- 4.10 使用者及權限
- 4.11 外掛
- 4.12 圖片及附件的處理
- 4.13 敏感詞過濾及迴響審查
- 4.14 靜態化
- 4.15 通知系統
- 部落格協定或標準
- 5.1 RSS
- 5.2 ATOM
- 5.3 OPML
- 5.4 APML
- 5.5 FOAF
- 5.6 BlogML
- 5.7 Open Search
- 5.8 Pingback
- 5.9 Trackback
- 5.10 MetaWeblog
- 5.11 RSD
- 5.12 閱讀器檢視
- 設計部落格系統有哪些知識點
- 6.1 時區真的全用 UTC?
- 6.2 HTML 還是 Markdown
- 6.3 MVC 還是 SPA
- 6.4 安全
- 結束語
01 文章 (Post)
我們每天可能都會閱讀或長或短的 3-5 篇文章。文章是部落格系統的核心業務,因此部落格文章的內容和品質非常重要。
那麼,文章這個業務類型如何命名?資料庫的資料表名稱和程式的變數名稱,類型名稱用 article 嗎?好像上學時候只學過文章叫做 article。其實部落格類型的文章,正確的表達是 post,英文單詞裡 post 和 article 的區別在於,post 只是隨心所欲寫的文章,而 article 指的是論文那樣經過精心雕琢,旁徵博引,並且有可能在學術期刊上發表的文章。因此設計部落格系統的時候,盡量避免使用 article 這個單詞來命名程式碼。更具體來講,post 中可以出現不嚴謹、口語化的表達方式,例如本文就算是個 post。而 article 講究言語上的規範,連「讓我們」,「我們來看看」這種字眼都不能出現。

文章需要具備標題、Slug、建立時間、發布時間、修改時間、摘要和內容等要素,也會包含所屬分類、標籤、閱讀量和點讚量等次要資訊。其中 Slug 是部落格的特色,它指的是一篇文章的 URL。例如我的文章:《Try the New Azure .NET SDK》,它的 URL 為 https://edi.wang/post/2019/12/5/try-the-new-azure-net-sdk,其中try-the-new-azure-net-sdk即為該文章的 Slug。Slug 講究的是「人類可讀」,一般情況下均為部落格標題對應的英文表達,用中劃線分割英文單詞,Slug 也對部落格的 SEO 起到了關鍵作用。如果你的部落格文章用的是資料庫 ID、文章標題的 HTML Encoding 等做 URL,請更換為 Slug。特別是遇到中文文章,如果標題被 URL Encoding 了,那麼對於 SEO 和連結分享,都是災難。一個 Slug 一旦定下,盡量不要改動,雖然大部分部落格系統都支援修改 Slug,但是對於被搜尋引擎收入的文章,改了 Slug 就會導致 404。比較完備的部落格系統(如 WordPress)支援採用 301 重新導向方式告訴搜尋引擎原文地址已變化。
摘要的有兩個作用,一是用於在列表檢視中顯示文章資訊預覽,二是用於 SEO,放在 description 這個 meta 標籤中,可以幫助搜尋引擎精準定位收錄的內容。對於中文內容,需要注意是否輸出的 HTML 原始碼被 Encoding 過,ASP.NET Core 預設的 Encoding 會對 SEO 造成災難(我的部落格系統因為面向英語使用者,不考慮中文支援,所以並不解決這個問題)。


摘要可以自動抓取文章前幾百字,也可以像微信公眾號那樣要求使用者手動填寫。我的部落格採用的是自動取文章前 400 字。結合 SEO 的關係,我的文章通常開頭段落就是概要,這樣可以讓使用者在搜尋引擎預覽頁面就能看到準確內容,而不是頁面上無關緊要的 UI 元素。

文章的狀態通常包括:草稿、發布、回收。使用者僅能看到已發布的文章,管理員可在後台更改文章狀態。
02 迴響(Comment)
迴響是部落格中作者和讀者互動的主要方式。有些部落格要求讀者登入後才能發表迴響,而有些可以允許遊客迴響(比如我的部落格及 WordPress)。登入的好處在於可以識別你的讀者,並有效防止垃圾迴響。但要求登入也會給使用者造成操作上多了一個步驟,嫌麻煩的使用者就不會進行迴響。
我的部落格及 WordPress 預設都設計為需要管理員在後台審核迴響後,才能放出顯示。這也能有效避免垃圾廣告、騷擾資訊甚至是一些惡意的煽動性言論。對於提供 Email 地址的使用者,管理員也能夠在後台回覆使用者的迴響,並由部落格系統向使用者發送 Email 通知。

對於技術部落格,迴響可考慮開放 markdown 格式。這是一種在程式設計師之間格外受歡迎的語法,在 GitHub 得到了廣泛應用。
迴響需要採用驗證碼或其他人機驗證技術,以防止機器人發廣告。但根據經驗,驗證碼並不能 100%阻止垃圾資訊,因為現代化的垃圾資訊還真的是人組團發的,有專門的公司、團隊、微信群等,國外也有。於是,你可能需要考慮關鍵字過濾,購買三方過濾介面等。
迴響也得記得做字數限制,不然也有可能會造成部分使用者「灌水」、洗版的現象。
如果不想自己寫功能,還可以整合三方的迴響服務,即部落格系統本身不實現迴響功能,透過三方服務載入外部 JS,在文章閱讀頁面「注入」一個迴響區,通常這要求文章的 URL 不變(WordPress 裡叫做永久性 URL)。
03 分類(Category)
像建立資料夾一樣將文章根據內容進行區分,即為分類。文章分類後,可以幫助讀者快速檢索同種類的文章。
例如寫.NET、PHP、JS 的文章都屬於「開發技術(Development)」這個分類。而技術圈新聞和職場經驗分享等文章,則屬於「工作」分類,分類的劃分完全由使用者控制。分類可以多對多。例如寫一篇文章介紹了用 ASP.NET Core 開發 Angular 應用的文章,可以同時屬於「.NET 技術」及「前端開發」分類。
分類需要一個標題、一個簡介,以及一個路由名稱。例如我部落格,微軟雲 Azure 的分類,標題為 Microsoft Azure,簡介為 The Best Cloud,路由名稱為 azure。標題需要同時顯示在標題欄,以便於 SEO。簡介是對於標題的補充說明,便於使用者檢視。設計路由名稱的原因請參考下一段介紹的標籤的設計。

分類的另一個功能就是產生 OPML 及 RSS/Atom 訂閱源,這個將在第五章介紹部落格協定中講解。
04 標籤(Tag)
一篇文章所提到的話題,即為文章的標籤。和分類一樣,標籤也是多對多關係。標籤可以作為檢索文章的依據,類似關鍵字,快速查詢相關內容的文章。
標籤需要考慮到標籤含義重複的情況,例如:VS 和 Visual Studio 是一個意思,VSCode、VSC 和 Visual Studio Code 也是一個意思。那麼使用者選擇標籤的時候,最好使用智慧提示推薦使用者使用已有標籤。
對於部落格系統設計者來說,還要考慮標籤的 URL。如果 URL 用的是標籤本身的內容,會導致很多問題。當標籤名稱為整個英文單詞,例如 Excel,並不會發生問題,因為 URL 通常是 https://yourblog/tags/excel。但是如果標籤內容為 .NET Core、C#、Robots.txt,事情就變的有意思起來。https://yourblog/tags/robots.txt 到底是在請求 tags 下的 robots.txt 檔案還是在請求標籤?自己作為部落格系統設計者,當然可以從程式上限制所有 tags 接受的路由參數都為標籤,好像是解決了問題,但 SEO 和掃描工具可不這麼認為,他們有大量 by convention 的規則會認為是請求檔案。
對於需要 URL Encoding 的標籤內容,更會導致 URL 缺乏可讀性,從而影響 SEO。千萬不要自作聰明地以為現代的搜尋引擎可以處理好 URL Encoding,一個 URL 是否乾淨對 SEO 的影響很大。特別是當標籤是中文內容的時候,如果全 encoding 了,URL 就會非常冗長,甚至影響到 SEO,也影響到部落客分享連結。因此,我的部落格系統為了處理標籤 URL,給每個標籤都設計了規範化名稱(normalized name),由系統根據標籤內容自動產生,如 .NET Core 經過 normalize,會變成 dotnet-core,最終產生的 URL 即 https://edi.wang/tags/list/dotnet-core。

對於使用者來說,最容易犯錯之一的就是把標籤用成搜尋關鍵字。例如使用者寫了一篇關於 Visual Studio Code 的文章,那麼標籤可能會同時打 VSCode、VSC 和 Visual Studio Code,但其實只要選擇一個標籤即可。打太多同樣含義的標籤會導致讀者無法完整檢索到所有相關文章,對搜尋引擎來說,也是如此。所以如何用好標籤,是部落格設計者和使用者需要共同關注的要點。
標籤雲(Tag Cloud)是部落格中用來列出最熱門標籤的功能。通常使用更大號字、更明顯的顏色來標識出對應文章較多的標籤。標籤雲可以作為部落格部落客的個人化屬性,一眼就能看出部落客熱衷於什麼話題(比如 Windows Phone?0.0)。
05 封存(Archive)
以時間(年、月、日)整理的部落格文章即為封存,它和分類的區別在於封存只以時間為標準來劃分文章。Archive 的 SEO 相對於文章、分類、標籤來說,並不那麼關鍵。所以除了 URL 可以按年月劃分以外,並沒有額外的講究。
例如:https://edi.wang/archive/2019/9 表示 2019 年 9 月的文章。https://edi.wang/archive/2019 則表示 2019 年所有的文章。封存功能主要用於給讀者按時間查詢,看看部落客某個時間都在幹什麼。設計這樣的功能可以提高讀者對部落客的興趣,也是個人對外形象的一種展示。

06 頁面(Page)
頁面是部落格的選用功能之一,事實上,它更接近於 CMS 的功能。有些內容並不適合以文章的形式發布,例如「關於」頁面。這樣的頁面通常與發布時候的時間無關,內容也經常更新,排版設計也非常自由,不單純是文字。
頁面通常不需要迴響、標籤和分類等屬性,但可以有發布和編輯時間。和文章一樣,頁面也需要注意 Slug。

在我的部落格系統中,頁面也選擇是否隱藏側邊欄,使用者也可以完全編寫頁面的 HTML 及 CSS 程式碼,並把頁面新增為導航選單。WordPress 對於頁面的處理更加完備,接近於 CMS 系統。
07 訂閱(Subscription)
讀者訂閱部落格的主要方式有 Feed(RSS/ATOM)及 Newsletter。Feed 方式本質上是被動訂閱,需要用戶端軟體發起請求給伺服器,檢查是否有新文章發表,才能顯示到用戶端裡。Newsletter 一般採用 Email 形式主動發送給訂閱使用者,但這要求部落格系統的編寫者實現 Email 訂閱功能,也要求管理員維護 Email 服務。訂閱一般只推送近期發表的新文章,例如前 10、20 篇,而不會每次都推送全部文章導致用戶端爆炸。

訂閱一般可按文章分類提供,以便於只對某些分類感興趣的讀者閱讀。有些部落格系統也提供文章迴響的訂閱源,以便讀者觀摩吐槽大會。
關於 RSS 及 ATOM 的詳細介紹請看 5.1、5.2 章節。
08 版本控制
更接近 CMS 的部落格系統通常提供版本控制功能,允許使用者回滾文章或頁面的歷史版本。設計版本控制的時候,不能只考慮往前回滾,得還能再滾得回來。通常,使用者每次編輯一篇已經寫好的文章,就會產生一個新版本,類似於 git 對於一個檔案的 commit。部落格的版本控制也類似於程式碼版本控制,你可以選擇儲存一篇文章的完整內容作為歷史版本,也可以選擇每次只儲存變化量資訊(delta)。儲存完整內容不容易後續花費大量時間精力 ,但是會佔用較多儲存空間。儲存內容變化量節省資料庫空間,但實現程式碼容易佔用大量精力。
09 主題及個人化
好用的部落格系統通常支援主題,畢竟個人化是部落格本身應有的特點之一。WordPress 積累了大量的主題庫,也允許自製主題。但是我的部落格只支援更改主題色,還有很大上升空間。
10 使用者及權限
部落格系統分為個人、團隊及部落格平台。個人部落格系統一般為單使用者(例如我的部落格),不需要設計權限、註冊等功能。多使用者部落格則需要實現不同的角色和權限,比如部落格管理員、審核專員、撰稿人、迴響管理員等等。無論是單使用者還是多使用者部落格,整合一套成熟的三方 RBAC 方案可能是最高效的選擇,多數三方方案也都支援 SSO,例如我部落格支援的 Azure AD。
11 外掛
外掛功能可以在不更改部落格程式碼的情況下,按需拓展部落格的功能。WordPress 以及 BlogEngine 都支援外掛,但 Moonglade 還不行。

12 圖片及附件的處理
圖片格式
在 2020 年,圖片格式已經非常自由,一般的部落格 JPG 居多,程式設計師的部落格 PNG 居多(畢竟都是螢幕截圖),像微信公眾號那樣採用 WEBP 格式現在同樣可取,只要讀者的裝置相容即可。一般 BMP 格式由於體積大會導致網路傳輸慢,所以不推薦。同樣道理,GIF 也要注意限制尺寸。
部落格系統輸出圖片時,需要採用正確的 Mime Type,以保證用戶端的相容性。一般直接輸出靜態檔案本身不需要部落格編寫者手動處理 Mime Type,但有專門圖片處理邏輯的部落格(例如我的 Moonglade)則需要留意保留圖片原本的 Mime Type。
圖片浮水印
給上傳的圖片自動加浮水印有助於保護版權,浮水印內容一般是部落格的地址或部落客名字。添加浮水印時要注意圖片尺寸調整浮水印的比例,以免擋住圖中重要內容影響閱讀。對於過小的圖片,可選擇性的忽略浮水印。
另外,考慮到部落格有可能會在發展過程中改名,建議添加浮水印的時候在系統中保留一份原始圖片,以便於後期更新浮水印內容。
具體方法可參考我的文章《ASP.NET Core 給上傳的圖片加浮水印》。
圖片儲存
圖片存哪裡是個值得思考的問題。一般有 3 個地方存放:檔案系統、資料庫、雲上的 Blob 儲存服務。Moonglade 支援檔案系統及 Azure Blob 儲存。這三者各有優缺點。
檔案系統的優勢在於直接 serve static file 速度最快,但如果圖片目錄本身位於網站目錄底下,會導致目錄不只讀而引起潛在安全問題。比如早期 ASP 論壇系統裡流行過上傳改副檔名的 web shell,儘管給 web 伺服器上傳可執行檔案在 2020 年已經基本絕跡了,但依然存在隱患,就好比就算你家裡請了 007 當保鏢也是需要夜間鎖好門。
資料庫存圖安全性最高,並且讓部落格的資料只位於一個位置,方便管理和備份,十幾年前很流行這麼做,但其實讀寫圖片對資料庫有一定開銷,並且再由網站輸出,雙倍開銷,一般不推薦。
而雲端 Blob 儲存服務目前來說是最適合這個時代的方案,將圖片儲存在 Blob 中不僅能保證伺服器目錄唯讀,又能採用雲本身的安全特性限制非正常存取,還能透過 CDN 加速圖片輸出。要硬說缺點,就是雲服務需要額外的金錢,而沒錢,是自己的問題,不是雲的問題。

圖片防盜鏈
作為網站開發者,我們有時候不希望自己網站的圖片被其他網站直接引用。這在某些場景下會導致自己資料中心裡巨大的頻寬消耗,也就意味著別人使用我們的圖片,我們要為此付錢。例如,你的網站是 a.com,你有一張圖片是http://a.com/facepalm.jpg,而b.com在他們的網站上使用一個img標籤來引用了你的圖片,這導致網路請求是進入你的資料中心,消耗你的資源。因此部落格可選擇性的啟用防盜鏈功能,具體方法可參考我的文章《ASP.NET / Core 網站圖片防盜鏈》。
附 件
通常程式設計師的技術部落格會提供讀者下載程式碼範例等附件。設計附件功能和設計圖片儲存非常類似,完全可行。但我更建議技術部落格將程式碼範例等附件託管到其他網站(例如 GitHub)提供讀者下載。
自己部落格實現附件下載的壞處有:
大檔案
不同的 Web 伺服器及防火牆產品對檔案尺寸的限制不同,而部署部落格的使用者很可能無權管理這些限制,就會導致大附件無法提供下載。
域及 IP 黑名單
某些公司或組織(特別是安全規範較高的軟體公司)會屏蔽非白名單域的檔案下載,儘管你可以用瀏覽器正常打開該域的網頁,但無法下載檔案(防火牆只允許 HTML/CSS/JS 等,而不允許 ZIP、EXE 等)。而程式設計師部落格的讀者很有可能就處在這樣的公司裡。
CDN 資源耗費
如果你的附件較多,較大,並且你也像設計圖片儲存一樣給附件系統套了個 CDN,此時根據 CDN 服務商計費模式的不同,如果按流量計費,恐怕你的附件下載會導致你的錢包加速瘦身。
而採用三方檔案下載(如 GitHub、OneDrive)的好處有:
√ 你的檔案不僅可以分享到部落格文章中,也可以分享到別的位置;
√ 這些三方服務有自己的 CDN,而不用擔心消耗你自己的錢包;
√ 許多檔案託管服務有完整的管理功能,例如檔案刪除、復原、版本控制、權限等,要是自己在部落格系統裡寫一個這個,需要花費大量時間……
13 敏感詞過濾及迴響審查
部落格難免引來一些抱有敵意的人,也會引來發廣告的人,所以通常需要敏感詞過濾和迴響審查。如果沒有審查直接將使用者的迴響顯示在文章下,那麼可能會對部落客和網站本身帶來不良影響。例如,有人發了政治敏感的言論或者不合規的廣告,沒有經過後台審核就直接顯示出來了,而你的部落格部署在大陸,那麼你的部落格很可能會被馬上關停整頓,並且自己也會解鎖程式設計師從入門到入獄的成就。也千萬不要以為部署在境外就沒事了,一些仇恨性質的言論甚至可以幫你引來駭客,在你的部落格裡下毒,勒索你或你的讀者。

因此我強烈建議個人部落格啟用敏感詞過濾及迴響審查功能。WordPress 及我的 Moonglade 部落格系統均支援敏感詞過濾和迴響審查。
14 靜態化
早期的新聞系統、部落格、CMS 為了提高大訪問量下的回應速度,都會採用靜態化技術,即將伺服器端渲染完的頁面儲存為真正的 HTML 檔案於磁碟上,進行 static file 的輸出,Web 伺服器輸出 static file 的效率非常高,對於不變的內容,使用者的後續訪問不會 hit 資料庫,因此極大減小了伺服器的壓力。在 2020 年的今天,靜態化已經不是唯一的方案,Redis Cache 也可以幫助我們減少對資料庫的頻繁存取。對於個人部落格來說,如果你的訪問量不高,其實並不需要 996 一個靜態化或 Redis 出來增加開發和維護成本。但如果你設計的是部落格平台,那麼最好還是用上靜態化或 Redis 吧。
15 通知系統
部落格通常透過 Email 的形式給管理員或使用者發送通知。但是沒有規範或約定表示部落格是否一定得使用 Email 進行通知推播,可由部落格系統設計者自行決定。
通知通常包括:
向部落客發送的通知:新迴響、文章被他人部落格引用(參見第 5.8, 5.9 章)。
向使用者發送通知:新文章發布(訂閱 Newsletter)、迴響被回覆、迴響審核通過或被拒。
Email 通知系統要注意垃圾郵件及使用者隱私保護問題。

垃圾郵件發給部落客本身問題並不大,但得注意郵件系統是否會允許未經部落客許可的針對讀者的郵件發送,其中可能會被人利用發垃圾郵件,從而導致伺服器被封禁。有些伺服器供應商,例如微軟 Azure,對於郵件有更加嚴格的規定,部署在部分 PaaS 業務上的程式碼呼叫 SMTP 終端會被直接屏蔽。
對於使用者隱私問題,在使用者向部落格系統提供 Email 地址的同時,需要告知使用者該 Email 地址會被如何使用(可寫在隱私協定或頁面可見區域),也可以讓使用者勾選是否允許部落客使用該 Email 進行通知推播。另一個問題是郵件地址暴露,這通常發生在 Newsletter 的訂閱群發,如果把所有使用者的 Email 地址都放在 To 或 CC 裡,那麼每個使用者都會知道其餘所有人的 Email 地址,從而互相約炮、詐騙,因此 Newsletter 請採用 BCC 或單獨發送,並允許使用者退訂。
Moonglade 的通知系統採用 Email 方式,但設計比較基礎。一個完善的通知系統需要採用訊息佇列及事件設計,並採用三方服務。例如 Azure 上可以使用 Storage Queue + Function App + SendGrid,以免遇到大量 Email 發送的時候原地爆炸。
下篇將主要介紹【部落格協定或標準】歡迎關注
