基于jQuery和Flash的多文件上傳插件uploadify的確很好用。但今天在用這個(gè)插件的時(shí)候遇到了一個(gè)非常頭痛的問(wèn)題,上傳文件的時(shí)候,我后臺(tái)的session突然都丟失了,我進(jìn)入調(diào)試去查看session變量發(fā)現(xiàn)為null。悲劇,難道我不能用這個(gè)插件了嗎?當(dāng)然不可能,這么好的東西當(dāng)然要用起來(lái),于是就去找解決方案了。
終于,答案有了,原來(lái)一般情況下(非IE瀏覽器),因?yàn)橹T如uploadify,swfupload采用的都是flash客戶端,這樣它們產(chǎn)生的useragent與用戶使用瀏覽器的 user-agent必然不同。所以,雖然用戶登錄了你的系統(tǒng)產(chǎn)生了一個(gè)session,但是當(dāng)觸發(fā)上傳程序時(shí)會(huì)產(chǎn)生另一個(gè)session(在上述 useragent選項(xiàng)開(kāi)啟的情況下)。所以,不是session丟失了,而是當(dāng)你上傳文件時(shí),CI為uploadify另外創(chuàng)建了一個(gè)session。好了,既然找到問(wèn)題的根源,我們就想辦法讓服務(wù)器在session判空之前將session值手動(dòng)傳遞過(guò)去。
在ASP.NET中的解決方案如下:
在上傳的那個(gè)頁(yè)面中加入以下代碼
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) {
},
'onSelectOnce': function (e, data) {
$('#fileInput1').uploadifySettings('scriptData', { 'ASPSESSID': ASPSESSID, 'AUTHID': auth });
}
});
注意上面有一句,很關(guān)鍵
$('#fileInput1').uploadifySettings('scriptData', { 'ASPSESSID': ASPSESSID, 'AUTHID': auth });
接下來(lái)我們必須在服務(wù)端Session判空并創(chuàng)建之前,將傳遞過(guò)來(lái)的SessonID強(qiáng)制賦給當(dāng)前請(qǐng)求的Cookies,這樣服務(wù)端就認(rèn)為還是原來(lái)的Session傳遞過(guò)來(lái)了。具體做法我們可以在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);
}
這時(shí)候你訪問(wèn)上傳文件的那個(gè)頁(yè)面時(shí)可能會(huì)報(bào)“會(huì)話狀態(tài)已創(chuàng)建一個(gè)會(huì)話 ID,但由于響應(yīng)已被應(yīng)用程序刷新而無(wú)法保存它”的錯(cuò)誤,這時(shí),你可以在web.config文件改變session的存儲(chǔ)方式,一般默認(rèn)都是以 “inproc”存儲(chǔ)的,我們把它改成stateserver模式,即在system.web節(jié)點(diǎn)下加入
<sessionstate mode="StateServer" stateconnectionstring="tcpip=127.0.0.1:42424" timeout="30"></sessionstate>
OK,問(wèn)題解決,雖然看起來(lái)解決這個(gè)問(wèn)題比較麻煩(不知道在其他網(wǎng)站中怎么弄,至少在.NET中比較麻煩),但這么好的一個(gè)文件上傳插件,這樣做很值得。希望能給遇到同樣問(wèn)題的朋友一點(diǎn)幫助。當(dāng)然如果你有更好的解決方案,可以留言告訴我,不勝感激。