基於jQuery和Flash的多文件上傳插件uploadify的確很好用。但今天在用這個插件的時候遇到了一個非常頭痛的問題,上傳文件的時候,我后台的session突然都丟失了,我進入調試去查看session變量發現為null。悲劇,難道我不能用這個插件了嗎?當然不可能,這么好的東西當然要用起來,於是就去找解決方案了。
終於,答案有了,原來一般情況下(非IE瀏覽器),因為諸如uploadify,swfupload采用的都是flash客戶端,這樣它們產生的useragent與用戶使用瀏覽器的 user-agent必然不同。所以,雖然用戶登錄了你的系統產生了一個session,但是當觸發上傳程序時會產生另一個session(在上述 useragent選項開啟的情況下)。所以,不是session丟失了,而是當你上傳文件時,CI為uploadify另外創建了一個session。好了,既然找到問題的根源,我們就想辦法讓服務器在session判空之前將session值手動傳遞過去。
在ASP.NET中的解決方案如下:
在上傳的那個頁面中加入以下代碼 var auth = "<% = Request.Cookies[FormsAuthentication.FormsCookieName]==null ? string.Empty : Request.Cookies[FormsAuthentication.FormsCookieName].Value %>"; var ASPSESSID = "<%= Session.SessionID %>"; 然后初始化插件的代碼改成如下形式 view sourceprint?$("#fileInput1").uploadify({ 'uploader': '/Scripts/uploader/uploadify.swf', 'method': 'GET', 'script': '/mystudio/GoUploadAvatar', 'cancelImg': '/Scripts/uploader/cancel.png', 'sizeLimit': 2048000, 'multi': false, 'fileDesc': '選擇jpg,png,gif', 'fileExt': '*.jpg;*.png;*.gif', 'onComplete': function (e, queueId, fileObj, response, data) { },
'scriptData': { 'ASPSESSID': ASPSESSID, 'AUTHID': auth },
'onSelectOnce': function (e, data) { $('#fileInput1').uploadifySettings('scriptData', { 'ASPSESSID': ASPSESSID, 'AUTHID': auth }); } }); 注意上面有一句,很關鍵 $('#fileInput1').uploadifySettings('scriptData', { 'ASPSESSID': ASPSESSID, 'AUTHID': auth });
接下來我們必須在服務端Session判空並創建之前,將傳遞過來的SessonID強制賦給當前請求的Cookies,這樣服務端就認為還是原來的Session傳遞過來了。具體做法我們可以在Global.asax文件中加入如下代碼:
protected void Application_BeginRequest(object sender, EventArgs e) { /* we guess at this point session is not already retrieved by application so we recreate cookie with the session id... */ try { string session_param_name = "ASPSESSID"; string session_cookie_name = "ASP.NET_SessionId"; if (HttpContext.Current.Request.Form[session_param_name] != null) { UpdateCookie(session_cookie_name, HttpContext.Current.Request.Form[session_param_name]); } else if (HttpContext.Current.Request.QueryString[session_param_name] != null) { UpdateCookie(session_cookie_name, HttpContext.Current.Request.QueryString[session_param_name]); } } catch { } try { string auth_param_name = "AUTHID"; string auth_cookie_name = FormsAuthentication.FormsCookieName; if (HttpContext.Current.Request.Form[auth_param_name] != null) { UpdateCookie(auth_cookie_name, HttpContext.Current.Request.Form[auth_param_name]); } else if (HttpContext.Current.Request.QueryString[auth_param_name] != null) { UpdateCookie(auth_cookie_name, HttpContext.Current.Request.QueryString[auth_param_name]); } } catch { } } private void UpdateCookie(string cookie_name, string cookie_value) { HttpCookie cookie = HttpContext.Current.Request.Cookies.Get(cookie_name); if (null == cookie) { cookie = new HttpCookie(cookie_name); } cookie.Value = cookie_value; HttpContext.Current.Request.Cookies.Set(cookie); }
這時候你訪問上傳文件的那個頁面時可能會報“會話狀態已創建一個會話 ID,但由於響應已被應用程序刷新而無法保存它”的錯誤,這時,你可以在web.config文件改變session的存儲方式,一般默認都是以 “inproc”存儲的,我們把它改成stateserver模式,即在system.web節點下加入
<sessionstate mode="StateServer" stateconnectionstring="tcpip=127.0.0.1:42424" timeout="30"></sessionstate>
OK,問題解決,雖然看起來解決這個問題比較麻煩(不知道在其他網站中怎么弄,至少在.NET中比較麻煩),但這么好的一個文件上傳插件,這樣做很值得。希望能給遇到同樣問題的朋友一點幫助。當然如果你有更好的解決方案,可以留言告訴我,不勝感激。