Continuity: 一種很不同的網頁應用程式寫法
作者:gugod 發佈於: ,更新於: #perl #continuity #webContinuity 是個給網頁應用程式所用的函式庫 (library),它很魔奇地處理了「session」這個概念,讓寫程式的人可以不必特別管理 session 內容的存放。
比方說,一個典型的 web cgi counter:
use Continuity;
Continuity->new(port => 5000)->loop;
my $counter = 0;
sub main {
my ($request) = @_;
$counter++;
$request->print("$counter\n");
}
# GET http://localhost:5000/
此處的 main
函式為 Web 程式的進入點。也是 Continuity 唯一需要其使用者去特別定義的函式。在此例中,$coutner
這個全域變數被遞增,然後以 $request->print
的方式,傳回給瀏覽器去顯示。
光這樣也這不覺得它有什麼神奇之處,那麼我們來亂加一下這個 counter 的功能: 當 counter 數到 10 時,要求訪客輸入大名,並在輸入後,顯示「某某某,您中獎了」的訊息,然後再將 counter 重置回 0,重新起算。
實做此功能的程式碼如下:
use Continuity;
Continuity->new(port => 5000)->loop;
my $counter = 0;
sub main {
my ($request) = @_;
$counter++;
if ($counter == 10) {
prize_winner($request);
}
$request->print("$counter\n");
}
sub prize_winner {
my ($request) = @_;
$counter = 0;
my $name = prompt_for_name($request);
$request->print("$name, you are the winner!");
$request->next;
}
sub prompt_for_name {
my ($request) = @_;
$request->print(<<FORM_FOR_NAME);
<html><body>
<form method="post" action="/">
<p>Tell us your name: <input name="name" type="text" /></p>
<p><input type="submit" value="Send">
</form>
</body></html>
FORM_FOR_NAME
$request->next;
return $request->param("name");
}
我將「告知中獎」及「問名字」拆成兩個函式,可以看見,main
函式本身變得相當的好讀。如果這個功能寫成桌面程式的話,也就是這種邏輯。
但請注意,這是個網頁程式,prize_winner
函式為了要問使用者大名,少說也要花去一個 request,並接受 form submit 回來。為何它可以被放在一個 'if' 條件之中 ?
Continuity
施展的魔法在於它通透地包裝了 http request/response,使得網頁程式設計的邏輯,可以跟桌面程式一樣。只有單一進入點,並可在要求使用者輸入時,暫停程式執行(嗯,至少看來很像如此)
暫且不管細節。看程式碼追蹤下去。prize_winner
取得使用者大名的方式是呼叫 prompt_for_name
函式,它的傳回值便是使用者輸入的名字。
再追下去,prompt_for_name
則是以 $request->print
送了一個 html form, 裡面有 "name" 這個欄位,然後呼叫 $request->next
,然後 $request->param("name")
便會有使用者大名了。
這個 $request->next
就是神奇的地方了。它會使這個程式流程「暫停」,等待使用者輸入(也就是送出表單)。在收到表單之後,繼續執行。
目前這個程式並沒有查使用者是否真的有輸入名字,他/她可能輸入的是空白。如果要再加上: 「檢查是否有輸入名字,沒有的話該就再次要求輸入」這樣的功能,要如何做 ? 答案很驚人: 寫個 while 迴圈去檢查便行:
sub prompt_for_name {
my ($request) = @_;
my $name;
while (!$name) {
$request->print(<<FORM_FOR_NAME);
<html><body>
<form method="post" action="/">
<p>Tell us your name: <input name="name" type="text" /></p>
<p><input type="submit" value="Send">
</form>
</body></html>
FORM_FOR_NAME
$request->next;
$name = $request->param("name");
}
return $name
}
這樣的邏輯跟寫終端機用的程式沒什麼兩樣。而且,在這個程式中,完全沒有特別處理 URL / Route / Session 的程式碼。雖然還是要知道一些關於 request
的知識,但像這樣的工具實在是大大地簡化了網頁程式的架構形式。仍然可以用 MVC 架構來整理程式碼,但再也不必把邏輯安排成「造出 Response」為終點的模式了。
我個人覺得這是近幾個月學習各種 Web framework / library 中最令我驚奇的一個工具了。雖說各家工具都是以簡御繁,不過像這種連「繁」在哪裡都不用知道的簡化法,只能說他真是太神奇了。而且目前的實做試起來也很穩定。我試著以 Markapl 及 Text::Template::Extended 來做為樣版系統,也都非常成功。由內附的範例看來,做 ajax-based server push 也不是問題。目前正繼續深入了解中。