我個人的理解是,看起來就像在Web環境中用戶端能訂閱服務端的事件,伺服器端通過事件去通知用戶端。如果伺服器端用 ASP.NET 來實現,可以利用 .NET 的事件驅動機制,很有意思,下面的範例程式碼將展示這一點。
先看Web前端js代碼:
代碼如下 |
複製代碼 |
jQuery(function ($) { function long_polling() { $.getJSON('/comet/LongPolling', function (data) { if (data.d) { $('#logs').append(data.d + "<br/>"); } long_polling(); }); } long_polling(); }); |
js代碼很簡單,就是一個遞迴調用(調用在callback時進行的),通過jQuery的$.getJSON發起Ajax請求,'/comet/LongPolling' 表示請求的服務端 CometController 的 LongPolling Action 的網址。這裡我們可以看出實現 Comet 的痛點不在 Web 前端,而是在伺服器端。
接下來重點看 Web 服務器 ASP.NET MVC Controller 的代碼。
首先要注意的是為了響應 XMLHttpRequest long polling 請求,我們需要實現一個非同步控制器(AsyncController),如果您對 AsyncController 不熟悉,建議閱讀MSDN上的文章 Using an Asynchronous Controller in ASP.NET MVC 。
先上 Controller 的實現代碼:
(註:該控制器實現的功能是每隔5秒鐘向用戶端發送伺服器當時間)
代碼如下 |
複製代碼 |
public class CometController : AsyncController { //LongPolling Action 1 - 處理用戶端發起的請求 public void LongPollingAsync() { //計時器,5秒種觸發一次Elapsed事件 System.Timers.Timer timer = new System.Timers.Timer(5000); //告訴ASP.NET接下來將進行一個非同步作業 AsyncManager.OutstandingOperations.Increment(); //訂閱計時器的Elapsed事件 timer.Elapsed += (sender, e) => { //儲存將要傳遞給LongPollingCompleted的參數 AsyncManager.Parameters["now"] = e.SignalTime; //告訴ASP.NET非同步作業已完成,進行LongPollingCompleted方法的調用 AsyncManager.OutstandingOperations.Decrement(); }; //啟動計時器 timer.Start(); } //LongPolling Action 2 - 非同步處理完成,向用戶端發送響應 public ActionResult LongPollingCompleted(DateTime now) { return Json(new { d = now.ToString("MM-dd HH:mm:ss ") + "-- Welcome to cnblogs.com!" }, JsonRequestBehavior.AllowGet); } } |
實現非同步控制器需要繼承 System.Web.Mvc.AsyncController,並將 Action 分解為兩個,比如 Action 叫 LongPolling,則分解為 LongPollingAsync 與 LongPollingCompleted 。LongPollingAsync 接受用戶端請求,並發起非同步作業;非同步作業完成,調用LongPollingCompleted。
AsyncManager.OutstandingOperations.Increment(); 告訴ASP.NET接下來將進行一個非同步作業。
AsyncManager.OutstandingOperations.Decrement(); 告訴ASP.NET非同步作業完成,請調用LongPollingCompleted()方法。
範例程式碼中的非同步作業就是將伺服器目前時間作為參數傳遞給 LongPollingCompleted() 方法,LongPollingCompleted() 擷取伺服器目前時間並傳遞給用戶端,用戶端收到後將之顯示出來,將繼續發起 Ajax 請求 ... 這樣周而復始,實現了基於 XMLHttpRequest long polling 的 Comet。