SoLiD(Social Linked Data)是萬維網發明者Tim Berners-Lee提出的以Web爲基礎的、以用戶爲中心的Web 3.0概念。本博客前面有幾篇文章對其進行了一定介紹(如《Solid——簡介與體驗》、《搭建Solid Community Server》),也嘗試解釋了一些理念。
然而由於Solid和當今的Web 2.0的理念不同,並且以RDF / Linked Data(LD)爲數據基礎,它的開發對一些人來說有不少門檻。再加上現有文檔存在不好理解(比如許多文檔是協議Spec而並非常見的例子)或者碎片化的問題,開發的上手難度則會更高。本文(本系列文章)將嘗試對其中最核心的一些內容進行梳理,方便新開發者迅速把握要領——尤其是以中文爲母語的開發者,畢竟大部分文檔都是英文。
當前這篇會整體性地梳理一些最核心的理念,而後續文章則會針對一些具體的話題(比如現有的庫或LD等領域)分別。
由於Solid仍然在演進,本文會以現有標準爲基礎進行討論。在個別地方,如果某個已知即將進入標準的功能會帶來改變(一般是積極改變),我也會將其納入討論。
Solid的Web 3.0和Web 2.0開發的核心區別
如果用一句話來概括Solid的Web 3.0和現今的Web 2.0的區別,那麼就是:Web 3.0是以用戶爲中心,而Web 2.0是以服務爲中心。
這裏我仍然帶上前綴說「Solid的Web3.0」,是因爲它存在和區塊鏈所稱的Web3之間進行混淆的可能。本博客之前有一篇文章《論Web3.0和Web3》對此進行了梳理和討論。由於我更認同Solid的Web 3.0而非區塊鏈的,而且本文介紹的是Solid,所以後文將不再進行區分。
Web 3.0和Web 2.0本身的不同
在說開發區別前,我們首先要說明二者背後概念的區別。
Web 2.0下,我們做任何事要首先訪問一個站點(比如google.com),然後在其上完成後續所有功能;如果需要存儲數據,那麼需要在該站點上註冊賬戶/身份(比如谷歌賬號),然後將數據存放在該站點的服務器中。多數情況下我們其實不怎麼區別站點的服務器和其相關的其他服務器,而僅僅將它們統稱爲平臺(畢竟我們作爲用戶也沒法控制)。一個平臺背後是一個服務商(比如谷歌),而一個服務商可能同時運行多個站點(比如谷歌同時運行www.google.com、play.google.com等站點,StackExchange同時運行stackoverflow.com、superuser.com等站點)。一般情況下一個服務商的站點數據(用戶身份)會做到互通。但如果想要跨服務商?抱歉,做不到。
最近這些年隨着例如OpenID/OIDC的SSO(Single Sign-On,單站登錄)機制在一些站點受到支持,該現象得到了一點改善:用戶不需要在每個網站輸入自己的密碼了,而只用選擇使用一個SSO賬戶(比如GitHub)登錄;用戶暱稱一般也都可以直接複製過來。但本質上,絕大多數站點背後仍然使用相同的邏輯:站點數據存儲在本站的服務器中,而非SSO賬戶背後的服務器中(比如GitHub)。
雖然這裏說是Web 2.0,但這個模式深刻影響了這個時代的絕大多數服務,也包括非(狹義)Web的在線服務,比如類似QQ、Telegram的各種即時通信軟件,各種網絡遊戲等。
而Web 3.0下,用戶擁有自己的身份(WebID)、擁有自己的數據存儲庫(Solid Pod)。當需要使用某個功能時,會去訪問一個Solid App(比如https://umai.noeldemartin.com),然後在該Solid App上登錄自己的WebID;該App會從用戶的Solid Pod中存取數據,而非在自己的服務器上。這樣,一個WebID可以用在所有的App上,而不需要重新註冊賬號;Solid Pod中的一套數據也可以用在所有App中,而不用重新輸入;用戶***可以自己決定Pod在哪裏。
Solid之所以使用RDF/LD爲主要數據結構,也是爲了更好地支持跨App的數據共享,也就是數據的互操作性(interoperability)。另外,很理所當然的,一個人可以有多個WebID,一個WebID也可以有多個Solid Pod。這些靈活性都是Solid所追求的。
Web 3.0和Web 2.0開發的不同
從上面討論中,我們其實已經看到了Web 3.0和Web 2.0開發的核心區別:Web 3.0中不再具有Web 2.0中包攬並控制全部的「平臺」,而是將其分解爲了提供功能的App、提供身份的WebID和提供存儲的Solid Pod。
換句話說:Web 3.0開發中,開發者只需要開發App,而不用爲了許多基礎功能(比如用戶身份、存儲)而開發服務端內容。這對開發者和用戶來說都是好事:
- 開發者可以減少對用戶身份(用戶名表、密碼混淆)、安全(數據泄漏)等方面的考慮或者顧慮,因爲這都不再託管在自己的服務器上;
- 用戶數據存儲在用戶自己的Pod中,可以隨時中斷App對數據的訪問,用戶可以更容易信任App;
- 數據已經存在Pod中,所以用戶可以隨時使用相兼容的其他App訪問同一數據而不用擔心更換App丟失數據,而開發者也同樣可以得益於已有數據而避免冷啓動(Cold Start)的問題。
Solid鼓勵ephemeral(轉瞬即逝的、生命短暫的)App,即一個App自己不存儲數據,所有用戶數據全部讀取自和存儲在用戶的Pod中。典型的比如加載一個(靜態)站點到瀏覽器中,然後所有功能全部由JS實現,數據存儲在Pod中,或將緩存儲存在瀏覽器中(注意這些緩存可以隨時拋棄重建)。
另外,以用戶爲中心其實帶來一個副作用,那就是我們明確認識到App不具有「全局」視角或「全部」數據——其實在Web 2.0中也是一樣的,因爲一個站點只有自己服務商數據庫中的數據而不具有其他服務商數據庫中的數據,但大家某種程度上選擇性地忽略了這個事實。如果需要多人的數據,那就需要動態/即時從多個用戶的Pod中讀取數據。這可能帶來效率問題,所以有人嘗試使用各種方案的緩存來改善效率。本質上這和使用CDN或其他緩存節點改善Web 2.0沒有太大區別,但Solid上有時需要考慮隱私等問題(Web 2.0則不需要考慮,因爲不行),可能更複雜一些。
什麼是Solid App?和Solid Pod怎麼交互?
作爲一個開發者,在Solid上進行的開發一般都是指Solid App的開發。而如其名稱所示,Solid App就是遵從Solid協議的App(應用程序)。
如前面已經梳理的那樣,Solid App是將原先捆綁在一起的業務、身份和存儲三者拆分開後,「業務」這個概念的體現。這一拆分其實解放了開發者,因爲這樣App開發者只需要操心App本身的業務邏輯,而不用操心數據存儲和用戶身份維護等問題。這對小型團隊尤其有利,因爲可以省去處理安全、法規等的成本,也可以省去一大筆維護用戶信息服務器的成本;並且,由於數據的互操作性,新開發者往往不需要擔心冷啓動的問題,因爲可以直接使用Pod中的已有數據。
由於Solid是以Web爲基礎,典型狀態下一個Solid App就表現爲一個網頁/網站,通過瀏覽器訪問。用戶從該App登錄他的WebID,然後App從WebID中獲取用戶信息,包括Pod位置,然後在有需要的時候從(向)Pod中讀(寫)數據。
不過其實Solid協議並沒有強制規定Solid App的實現形式,所以一個Solid App也完全可以是其他形式,比如一個手機App。
Solid Applications這個頁面整理了一些以網頁實現的Solid App,而澳大利亞Solid社區開發的許多Solid則是Web、桌面、智能手機全端支持。
從底層來說,Solid App和Solid Pod的交互是通過Solid協議。當然,有大量的現成的庫來協助開發者,讓我們不用去探究那麼底層的事情,而只用關注高層的功能。所以只要掌握了Solid或者說Web 3.0的理念,Solid App開發和Web 2.0的(Web) App開發沒有太大區別。
RDF和數據格式
Solid的一個特點是圍繞RDF構建,推薦數據存儲成RDF結構,比如序列化成Turtle或JSON-LD文檔,因爲這可以帶來最大化的數據互操作性。但Solid並不強制要求數據以RDF結構存儲,所以也完全可以存放其他類型的數據——其實有些數據類型天生就不合適用RDF存儲(比如位圖),Solid很自然地不可能不去試圖支持它們。
但在條件允許的情況下,我還是推薦儘量使用RDF來存儲數據。除了互操作性及RDF相關工具的幫助外,RDF結構的數據本身也很清晰易懂,對App的後續維護也有幫助。對不熟悉RDF的人來說,或許最簡單的一種過渡方案就是首先將數據存儲爲JSON,日後再將其遷移爲JSON-LD。本文不深入討論這點,等後續文章寫完了會在此放置超鏈接。
RDF的各種序列化格式(比如JSON-LD和Turtle)都是可以自動互相轉換的,Solid原生支持這點,只需要在HTTP請求頭中聲明自己需要的格式即可。
對RDF、LD等知識感興趣的讀者可以看我的另一篇文章《語義網和關聯數據(淺層)知識梳理》。本文不展開討論。
WebID和用戶身份
作爲用戶身份標識,WebID有環繞其而存在的一些列標準或協議(例如Solid-OIDC)。對於開發者來說,除非你的App功能裏包含修改WebID內容的需求,否則你的App只會涉及讀取用戶提供的WebID,而不包含寫入或創建它。
一般情況下,當在某個Solid服務上註冊賬號後,它都會自動給你(用戶)生成一個WebID,並存放在你的Pod中。取決於具體的Solid服務提供方和軟件,你可能有機會爲同一個賬號額外創建更多的WebID(比如從v7.0開始的Community Solid Server就支持這個功能)。
WebID以一個URI(例如URL)來標識,而這個URI(當對它執行GET方法後)對應的則是一個有特殊規定的RDF文檔。它的具體內容規定參見Solid WebID Profile,但大體來說包含如下內容:
- 如何鑑別用戶身份真僞
- 比如
solid:oidcIssuer
- 比如
- 用戶的信息
- 比如
foaf:name
- 比如
- 用戶的Solid Pod(們)在哪
- 即
pim:storage
- 即
- 用戶的數據相關的額外信息
- 比如
solid:publicTypeIndex
- 比如
從功能上看,WebID是用戶最核心的文檔,也是App去「瞭解」用戶的入口。Solid App需要/應該從WebID的內容去「發現」或者說「識別」用戶的其他信息,比如如何鑑別用戶身份,以及用戶的Pod在哪裏等。 因此,當登錄Solid App時,一種常見的方式就是要求用戶輸入其WebID,然後App自動發現對應的Solid-OIDC服務,然後重定向過去進行後續的步驟(另一種就是要求輸入Solid-OIDC提供商地址,然後重定向過去,進行後續)。
有一點值得注意:許多Solid服務自動生成的WebID會形如https://a-solid-service/profile/card#me
,其中的#me
這個anchor是必要的,不能省略。這個WebID它是指向了https://a-solid-service/profile/card
這個RDF文檔中叫做#me
的一個節點,而這個#me
節點纔是真正的WebID Profile結構。
最後,WebID文檔未必要放在Solid Pod中。許多Solid服務將它放在Pod中只是出於習慣和方便考慮,而另一些(比如ESS)則將它放在Pod之外。放在Pod中的確存在一定潛在安全風險(比如這個討論),社區仍在討論更理想的解決方案。但這都並非App開發者需要在意的問題,除非開發者使用了非標準的方式來從WebID Profile中獲取信息。
Solid Pod提供的功能
既然Solid Pod是Solid的一個核心,而且是歸屬用戶的,那麼我們(尤其是作爲開發者)有必要知道一個Solid Pod本身提供什麼功能,以便合理區分哪些功能是App要提供的,哪些是直接交給Pod完成的。
如果作爲Pod的所有者,如果我想去查看Pod的內容,還是需要使用一個Solid App來完成。一般情況下,一個Solid服務也會提供一個默認的界面供用戶使用(本質上就是這麼樣一個Solid App),比如Mashlib或者叫SolidOS。如果想嘗試別的,這個列表列舉了一系列進行Pod管理的App。
大體來說,Solid Pod提供這麼一些核心功能:
- 身份認證——Solid-OIDC
- 數據管理——增刪改查
- 對於RDF數據,還有額外的功能,比如:
- 請求時對各種RDF序列化格式的自動轉換
- 直接對RDF文檔進行patch(增量修改)
- 對於RDF數據,還有額外的功能,比如:
- 文件組織——類似文件系統的Container和Resource的層級組織
- 權限管理和檢查——設置某個資源可以和不可以被誰(什麼身份)使用
- 外部輸入——Inbox機制
- 本質上Inbox是特化的一個具有(公衆或特定人)可寫權限的Container,但它作爲LDP的通用機制存在
- 實時通知——訂閱通知頻道
可以看到,對於構建一個App來說,所有關於數據維護和身份認證的功能都已經由Solid Pod提供,而App只要操心業務邏輯即可。
同時我們也可以看到,Solid作爲Web 3.0擁有一個區塊鏈所難以完成的優勢:存儲和分享私有數據。其核心就在於數據存放在用戶的Pod中,而非公開的區塊鏈上;權限檢查和授予也發生在Pod中,而非區塊鏈上的智能合約;這二者都可以隨時隨意修改。
這些全部都是Solid協議所規定的能力。其中部分能力由單獨的協議或規範所規定,例如更早就標準化的LDP,或是Solid自己制定的Solid Notification。至於它們的細節和使用,請參閱相關文檔、其他人的文章或本系列後續文章。
常見庫
有許多現成的庫和工具都在嘗試幫助Solid開發和調試,其中有的本身就是爲Solid開發,也有的是圍繞LD而同時支持Solid,還有的是其他泛用庫且(優先)支持Solid。這裏簡單列舉一些我覺得有必要知道的庫(以及我的評價):
- 用戶登錄
- Inrupt的Solid Client(
solid-client-authn
)- 有面向瀏覽器和面向nodejs的兩款
- 最常用的登錄相關庫
- Inrupt的Solid Client(
- Solid數據管理
- Jeff的Solid File Client
- 以文件和文件系統的概念操作Solid Pod
- 取決於用途,有時可能很好用,有時可能不合適
- Inrupt的Solid Client
solid-client
用來讀寫數據- 很低層,我個人不太推薦
solid-client-access-grants
用來編輯權限- 同時支持WAC和ACP,包括同時兼容二者的接口
- Jeff的Solid File Client
- RDF查詢和編輯
- Comunica:一個全能的SPARQL工具
- 它會自動決定是在客戶端還是服務端運行SPARQL,很通用
- LDO (Linked Data Objects):一個將LD數據映射爲TS/JS object的庫
- 它的理念我很喜歡,既自然又好用
- 但需要先寫Shape(形狀),對初學者不見得友好(但開發者也在嘗試通過提供形狀倉庫來改進)
- 另外有個有些類似的庫LDflex,但似乎維護不太好
- Soukai:一個ORM類的庫,將RDF數據映射爲TS object
- 理念更接近傳統的(關係型數據庫的)ORM
- 使用TS的class來定義數據結構,而非像LDO一樣使用Shape來定義
- rdf.js:定義並統一了在JS上操作RDF數據的接口和操作,並列舉了很多在此基礎上可互操作的庫
- 當需要直接處理具體的RDF文檔時很好用,但不需要這種低層操作時不推薦
- Comunica:一個全能的SPARQL工具
如前文所述,RDF不是必須,所以暫時不打算使用RDF的話可以先不看所有RDF相關庫。如果想學RDF(我個人十分推薦),或者已經熟悉RDF但想更多地瞭解相關工具,可以考慮看一看https://rdfjs.dev/這個網站,它對JS上可用的RDF工具進行了整理和說明(未必都是圍繞Solid的庫,但很多都支持Solid)。
尋求幫助和參加活動
Solid社區十分友好,並且很原意幫助新來者,所以有問題可以直接去社區詢問。官網的這個頁面對此有總結。主要的渠道有這些:
另外,Solid社區也有各種活動:
- Solid World:面向公衆的webinar,會有人講一些他們在Solid上做的東西
- 前兩年是每月一次,但今年由於種種原因並不穩定
- 日常線上聚會:各個開發組或主題的聚會,一般一週或兩週一次,一般都在Jitsi(jit.si)平臺上
- 我個人是先參加的SolidOS聚會,然後和人們混熟了
- 現在有了主題更明確的Solid Practitioner聚會,面向圍繞Solid的開發者
當然,這些都是英文的,可能會有一定心理障礙。但其實社區裏(尤其是論壇或聊天羣裏)不少人英語也都不怎麼好,所以不用擔心。至於中文渠道,我知道有Solid中文網,但沒能加入羣組(我不怎麼用QQ和Telegram),所以不確定是否仍然活躍。但如果你有什麼問題而且需要用中文提問,我很樂意儘量解答。最推薦郵件,但也歡迎從任何渠道聯繫我——發現聯繫我的渠道其實不難,但也不是傻瓜式的。
您可以在Hypothesis上的該群組內進行評論,或使用下面的Disqus評論。