Lisplets:彌合 Lisp 與 Java Servlets 之間的鴻溝
在 2000 年代初期,想要開發 Web 應用程式的 Lisp 開發者常面臨兩難:要麼重新發明輪子——自行編寫 HTTP 伺服器與 SSL 處理程式,要麼犧牲語言的彈性。於是 Lisplets 應運而生,這個於 2004 年由 Rich Hickey 創建的專案,旨在提供 Lisp 友善的 Java Servlets 介面。
Lisplets 如同一座橋樑,讓開發者能利用基於 Java 的 Web 環境(如 Tomcat、Jetty 或 Resin)的工業級功能,同時以 Common Lisp 或 Scheme 撰寫實際的應用程式邏輯。透過將 Web 的「管線」工作交給 Java,Lisp 開發者即可專注於語言的表達力,而不必犧牲可擴展性或安全性。
Lisplets 的運作方式
在核心上,Lisplets 由一個實作 HttpServlet 的單一 Java 類別組成。它不在內部處理請求,而是將請求轉發並使用 s-expression 透過 TCP socket 取得回應。
請求流程
- Interception: Java servlet 容器收到 HTTP 請求。
- Packaging: Lisplet servlet 將請求標頭、參數、Cookie、session 資料、應用程式狀態與使用者資訊封裝成單一 s-expression。
- Transmission: 此 s-expression 透過 TCP socket 傳送至監聽中的 Lisp 程序。
- Processing: Lisp 程序使用標準
read函式讀取 s-expression,處理邏輯並產生回應。 - Return: Lisp 程序回傳包含狀態、標頭與 session 狀態的 s-expression,接著是原始文件內容。
對 Lisp 開發者的主要優勢
透過使用 Java servlet 容器作為前端,Lisplets 帶來多項即時的好處:
- Infrastructure for Free: 開發者可取得專業的 HTTP 伺服器實作、SSL 支援,以及與業界標準 Web 伺服器的整合,且無需撰寫任何 Java 程式碼。
- Enterprise Features: Lisplet API 完整呈現 Servlet API 的功能,包括 session 管理、驗證、存取控制、使用者角色與宣告式設定。
- Hybrid Applications: 由於它在標準的 Java Web 應用程式內運作,Lisp 產生的內容可與 Java Server Pages (JSP) 或其他 Java Servlets 共同存在於同一應用程式中。
- Flexible Deployment: 它可在任何 servlet 容器上執行,讓開發者可依成本、嵌入性或平台支援等因素選擇環境。
技術深度探討:API
透過 web.xml 進行設定
Lisplets 透過標準的 web.xml 檔案進行設定。lisp-host 與 lisp-port 為必填項,用以定位 Lisp 程序;此外還有多個可選參數供微調:
lisp-tag-prefix: 允許開發者在標籤前加上字串(例如:),從而在 Common Lisp 中將其轉為關鍵字。lisp-create-session: 布林值,決定若不存在 session 時是否自動建立。lisp-roles: 以逗號分隔的清單,用於查詢使用者是否屬於特定角色,將 Lisp 邏輯與 Java 的驗證系統結合。
請求與回應格式
請求以單一的列表之列表形式傳送。每個子列表以標籤開頭(例如 :method、:uri、:headers、:session)。此結構讓 Lisp 程序能以標準的列表處理技巧輕鬆解析請求。
回應的結構亦相同。Lisp 程序必須至少傳送一個空列表 () 給 Java 端。回應的 s-expression 可控制:
- HTTP Status: 設定狀態(例如 200 OK)或觸發重新導向。
- Cookies: 定義名稱、值、域名與路徑。
- Session/Context Attributes: 更新 Java 端的動態屬性,並由 servlet 容器持久化。
- Logging: 直接將字串送至
ServletContext日誌。
實作範例
Rich Hickey 提供了一個為 Xanalys(LispWorks)編寫的示範伺服器,以展示整合的簡易性。該伺服器監聽一個埠口,從串流讀取 s-expression,並將請求回傳給瀏覽器作為回應主體:
(defun handle-lisplet-on-stream (stream)
(unwind-protect
(let ((req (read stream)))
(format stream "~S"
`((:status 200)
(:headers (:content-type "text/plain"))
(:log "Hello from Lisp")))
(pprint req stream)
(force-output stream)
(close stream))))
摘要
Lisplets 提供了一個優雅的解決方案,以應對經典問題:如何在使用高階且彈性的語言撰寫邏輯的同時,利用穩定且高效的基礎設施生態系。雖然此專案始於 2004 年,但其透過簡單、語言無關的通訊格式(s-expression)來橋接兩種不同執行環境的理念,仍是一個永恆的架構模式。
Sources
- HNLisplets