AJAX
在 AJAX 出現前,傳統網上軟件的用戶首先要學習的是等待。直到2005 年,Google Suggest 和 Google Map 等網上軟件出現,它們利用 XMLHttpRequest 和 Java Script ,讓網上軟件可以不用重新載入版面就能更新資料。這種即時回應大大改善了網上軟件的用戶體驗,JJG 把這種技術稱之為 AJAX 1。自此 Wep App 終於可以跟傳統軟件較量,AJAX 被認為是 Web 2.0 背後最重要的技術。
Comet
然而仍有一個問題要解決。AJAX 和傳統的網上軟件一樣只能單向地回應使用者的動作。除了由用者主動 polling 外,基本上軟件不能把消息發給用戶。講求群眾互動的 Web 2.0 竟不能作即時通訊,這種限制讓很多軟件也未能發展。2006 年,GTalk 和 Meebo 出現,它們利用持續的 HTTP connection,只用 HTTP 協定就能做到即時通訊的效果,Alex Russell 把這類技術稱之為 Comet 2 — 這不是任何字的簡寫,泛指事件導向、伺服器端 Push 資料的軟件。
Ruby on Rails 和 Web 2.0
Ruby on Rails 本身整合了 Prototype 和 Script.aculo.us ,開發者可以只用 Ruby on Rails 就寫出純正的 AJAX 軟件。相對來說 Comet 的工具在 Rails 上還未成熟,其中最容易的可算是 Juggernaut 。 Juggernaut 會在版面中加入 Flash 的 Juggernaut client ,它會跟 Juggernaut 的 Push Server 保持一個持續的 XMLSocket 連接,以接收 server 傳來的 javascript,用以更新 client 畫面。以下我會示範怎樣用 Juggernaut 做一個 Push 的網站。
系統要求
- Rails 1.1 或以上
- json gem (gem install json)
- eventmachine gem (gem install eventmachine 或 gem install eventmachine-win32)
使用方法
- 開啟一個新 project,安裝 juggernaut:
rails Realtime
cd Realtime
script/plugin install svn://rubyforge.org//var/svn/juggernaut/trunk/juggernaut - 新增一個 layout "apps/view/layout/application.rhtml" ,javascript_include_tag :defaults 一句是基本的 Rails helper , 在安裝 juggernaut 後會自動包括 juggernaut 的 javascript 檔。
<html> <head> <%= javascript_include_tag :defaults %> </head> <body> <%= yield %> </body> </html>
- 新增一個 controller "main":
./script/generate controller main index
- 按需要修改設定檔 "config/juggernaut.yml",暫時我們不用改任何東西。
- 新增一個 view "app/views/main/index.rhtml",form_remote_tag 是基本的 Rails AJAX function,它把 HTML FORM 的動作用 AJAX 送去 Server。listen_to_juggernaut_channels() 讓 client 在載入頁面後連接去指定 channel 接收 push 資料。
<h1>Push Demo</h1>
<%= listen_to_juggernaut_channels(['channel']) %>
<%= form_remote_tag :url => {:action => :push} %>
<%= submit_tag 'Push!' %>
<%= end_form_tag %> - 修改 "app/controllers/main_controller.rb",加入 push method。Juggernaut.send_data() 方法會向所有已連接的 Client 收到訊息。
class MainController < ApplicationController def index end def push Juggernaut.send_data("alert('Hello, world!')", ['channel']) end end
- 是時候測試一下成果!分別啟動 Rails 和啟動啟動 Juggernaut Push Server:
ruby ./script/push_server
Starting Juggernaut Push Server
Port: 15000
Host: 0.0.0.0./script/server
=> Booting Mongrel (use 'script/server webrick' to force WEBrick)
=> Rails application starting on http://0.0.0.0:3000
=> Call with -d to detach
=> Ctrl-C to shutdown server
** Starting Mongrel listening at 0.0.0.0:3000
** Starting Rails with development environment…
** Rails loaded. - 試著同時開啟兩個 browser 到 http://localhost:3000/,按下其中一頁的 "Push" 按鈕,兩個 browser 會同時彈出一個 javascript 的 alert message!
- 以上例子中,由 client 到 server 的訊息由 AJAX 發送,由server 到 client 的訊息由 Juggernaut 發送,這樣我們就有一個能雙向、即時通訊的軟件 model,至於怎樣利用這種強大的力量就要由開發者去想了!
- 當然 Juggernaut 還有其他功能,如對單一用戶發訊、動態加入和離開 channel 、用戶認證、以及在用戶開啟和關閉 Browser 時啟動 trigger action 。詳情可以參看 Nicolas Cavigliano 不斷更新的教學。 當然也可以讀 Juggernaut 的源碼 ,特別是 library "vendor/plugins/juggernaut/lib/juggernaut.rb" 和 Push Server "vendor/plugins/juggernaut/media/push_serve"
- 以上例子的源碼可以在此下載
研究 Juggernaut 時遇到的問題
- Flash 對 XMLSocket Connection 有許多限制。Juggernaut 的作者建議把 Push Server 放在 443 port ,讓軟件可以穿過 firewall。然而不知為何我的電腦上無論 Firefox 還是 Safari Flash 也不肯連去 443 port …
- 要注意 juggernaut.yml 的 HOST 和 URL ,如果你設定的是 localhost ,在 browser 中輸入 127.0.0.1 是絕對不會成功的!這是 Flash 的防止 cross site socket 機制。
- Client 和 Push Server 使用 Socket 連結, Rails 跟 Push Server 同樣使用 Socket:所有 Juggernaut 的 function 其實都會叫 Rails 開一個 Socket 連去 Push Server。每次發訊也要一個 Socket 在大型應用似乎不是一個好的想法 。
其他方案
Apache ActiveMQ 的 AJAX Polling 方案,似乎可以做到類似 Pushing 的效果,有待研究。
延申閱讀