線上人數異常處理過程
- 2009-07-24
- 14684
- 0
客戶經常性的會說我想知道線上使用人數有多人,製作方式大家都知道(不知道的Google一下一堆寫法...)但是 demo 今天遇到一個很有趣的事情,一個剛做好的專案一天上線人數也才4 ~ 5百人線上人數卻可以飆到1600多人...雖然我們都知道線上人數不會準,但這也太唬爛了...勢必需要修一下。
通用型的「線上人數」寫法都會利用 Application 來玩,所以很自然的在 Global.asax 中的 Session_Start() 撰寫 Code
protected void Session_Start() { Application.Lock(); if (Application["OnlineUserCount"] == null) Application["OnlineUserCount"] = 0; Application["OnlineUserCount"] = (int)Application["OnlineUserCount"] + 1; Application.UnLock(); }
protected void Session_End() { Application.Lock(); if (Application["OnlineUserCount"] == null) Application["OnlineUserCount"] = 0; Application["OnlineUserCount"] = (int)Application["OnlineUserCount"] - 1; if ((int)Application["OnlineUserCount"] < 0) Application["OnlineUserCount"] = 0; Application.UnLock(); }
這樣寫是很自然的,但是 demo 這次遇到這問題的原因是,客戶的網站來源訪客會大量的使用Proxy 造成瀏覽器不吃 Cookie 所以每次瀏覽一頁就會觸發三次 Session_Start() 然後就會很帥的發生按一頁線上人數+3的有趣事件,過程中嘗試不少寫法還是無法過濾,請了保哥幫我看看以後,保哥就想到了一個有趣的解法。
首先我們把 Session_Start() 的 Code 改成這樣
HttpContext.Current.Items["Session_Start"] = ""; Session["A"] = "";
然後再寫一個 ActionFilter
public override void OnActionExecuting(ActionExecutedContext filterContext) { if (filterContext.HttpContext.Items["Session_Start"] == null && filterContext.HttpContext.Session["A"] != null && filterContext.HttpContext.Session["B"] == null) { filterContext.HttpContext.Application.Lock(); if (filterContext.HttpContext.Application["OnlineUserCount"] == null) filterContext.HttpContext.Application["OnlineUserCount"] = 0; filterContext.HttpContext.Application["OnlineUserCount"] = (int)filterContext.HttpContext.Application["OnlineUserCount"] + 1; filterContext.HttpContext.Application.UnLock(); filterContext.HttpContext.Session["B"] = ""; } }
因為 demo 有習慣使用 BaseController 所以只需要將此 ActionFilter 附加到 BaseController 就可以讓使用者不管從哪個頁面進來都可以吃到了
[CookieCheck] public class BaseController : Controller
上面的 ActionFilter 中判斷了HttpContext.Items有沒有,以及Session["A"]、 Session["B"]是否有值,HttpContext.Items是一個很有趣的玩意,生命週期相當的短,想要詳細了解可以看看文章底部的參考的文章,這整段的邏輯就是,如果使用者有開啟 Cookie 那在「Session_Start()」就會同時賦予HttpContext.Current.Items["Session_Start"]和Session["A"]值,程式執行到 ActionFilter 時第一次就會順利的進入到 if 內部,而 if 的內部最後有賦予 Session["B"] 值,所以下次就不會進入此段 if 了,可以避免了那種線上人數瘋狂衝的詭異事情。
以上方法或許不是很優,如果各位有覺得恨好的作法歡迎提供。
回應討論