使用 Rails 和 Juggernaut 作即時通訊

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 資料的軟件。

Compare AJAX and Comet web model, originally from Comet: Low Latency Data for the Browser
Comet

Ruby on Rails 和 Web 2.0
Ruby on Rails 本身整合了 PrototypeScript.aculo.us ,開發者可以只用 Ruby on Rails 就寫出純正的 AJAX 軟件。相對來說 Comet 的工具在 Rails 上還未成熟,其中最容易的可算是 Juggernaut 。 Juggernaut 會在版面中加入 Flash 的 Juggernaut client ,它會跟 Juggernaut 的 Push Server 保持一個持續的 XMLSocket 連接,以接收 server 傳來的 javascript,用以更新 client 畫面。以下我會示範怎樣用 Juggernaut 做一個 Push 的網站。

系統要求

  1. Rails 1.1 或以上
  2. json gem (gem install json)
  3. eventmachine gem (gem install eventmachine 或 gem install eventmachine-win32)

使用方法

  1. 開啟一個新 project,安裝 juggernaut:

    rails Realtime
    cd Realtime
    script/plugin install svn://rubyforge.org//var/svn/juggernaut/trunk/juggernaut

  2. 新增一個 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>
  3. 新增一個 controller "main":
    ./script/generate controller main index
  4. 按需要修改設定檔 "config/juggernaut.yml",暫時我們不用改任何東西。
  5. 新增一個 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 %>

  6. 修改 "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
  7. 是時候測試一下成果!分別啟動 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.

  8. 試著同時開啟兩個 browser 到 http://localhost:3000/,按下其中一頁的 "Push" 按鈕,兩個 browser 會同時彈出一個 javascript 的 alert message!
    Push alert message!
  9. 以上例子中,由 client 到 server 的訊息由 AJAX 發送,由server 到 client 的訊息由 Juggernaut 發送,這樣我們就有一個能雙向、即時通訊的軟件 model,至於怎樣利用這種強大的力量就要由開發者去想了!
  10. 當然 Juggernaut 還有其他功能,如對單一用戶發訊、動態加入和離開 channel 、用戶認證、以及在用戶開啟和關閉 Browser 時啟動 trigger action 。詳情可以參看 Nicolas Cavigliano 不斷更新的教學。 當然也可以讀 Juggernaut 的源碼 ,特別是 library "vendor/plugins/juggernaut/lib/juggernaut.rb" 和 Push Server "vendor/plugins/juggernaut/media/push_serve"
  11. 以上例子的源碼可以在此下載

研究 Juggernaut 時遇到的問題

  1. Flash 對 XMLSocket Connection 有許多限制。Juggernaut 的作者建議把 Push Server 放在 443 port ,讓軟件可以穿過 firewall。然而不知為何我的電腦上無論 Firefox 還是 Safari Flash 也不肯連去 443 port …
  2. 要注意 juggernaut.yml 的 HOST 和 URL ,如果你設定的是 localhost ,在 browser 中輸入 127.0.0.1 是絕對不會成功的!這是 Flash 的防止 cross site socket 機制。
  3. Client 和 Push Server 使用 Socket 連結, Rails 跟 Push Server 同樣使用 Socket:所有 Juggernaut 的 function 其實都會叫 Rails 開一個 Socket 連去 Push Server。每次發訊也要一個 Socket 在大型應用似乎不是一個好的想法 。

其他方案
Apache ActiveMQ 的 AJAX Polling 方案,似乎可以做到類似 Pushing 的效果,有待研究。

延申閱讀


  1. Ajax: A New Approach to Web Applications
  2. Comet: Low Latency Data for the Browser
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章