一、jquery uploadify自我介紹:
(1)、大家好,我是jquery插件大家族中負責實現異步上傳的插件,我不是唯一,只是較好用的一款。
(2)、我的功能:
支援單一檔案或多檔案上傳,可控制並發上傳的檔案數
在伺服器端支援各種語言與之配合使用,諸如PHP,.NET,Java……
透過參數可設定上傳檔案類型及大小限制
透過參數可設定是否選擇檔案後自動上傳
易於擴展,可控制每一步的回呼函數(onSelect, onCancel…)
透過介面參數和CSS控制外觀
Uploadify主頁網址:http://www.uploadify.com/ 在該頁面你可以了解關於他的更多內容。
(3)、我的用法:
去baidu.com,google.com search search,且有許多。
二、firefox下我出故障了,是我的問題嗎?
jquery uploadify在ie下可以正常上傳,在實現非同步上傳的時候,每個檔案在上傳時都會提交給伺服器一個請求。每個請求都需要安全驗證,session和cookie的校驗。是的,就是這樣。由於jquery uploadify是藉助flash來實現上傳的,每一次向後台發送資料流請求時,ie會自動把本地cookie存儲捆綁在一起發送給伺服器。但firefox、chrome不會這麼做,他們會認為這樣不安全。哈,這就是原因。
找到原因了,在讓我們來理解兩個概念:
(1)、session:
Session又稱為會話狀態,是Web系統中最常用的狀態,用於維護和當前瀏覽器實例相關的一些資訊。舉個例子來說,我們可以把已登入使用者的使用者名稱放在Session中,這樣就能透過判斷Session中的某個Key來判斷使用者是否登錄,如果登入的話使用者名稱又是多少。
我們知道,Session對於每個客戶端(或瀏覽器實例)是“人手一份”,而使用者首次與Web伺服器建立連線的時候,伺服器會為使用者分發一個 SessionID作為識別。 SessionID是一個由24個字元組成的隨機字串。使用者每次提交頁面,瀏覽器都會把這個SessionID包含在 HTTP頭中提交給Web伺服器,這樣Web伺服器就能區分目前請求頁面的是哪一個客戶端。那麼,ASP.NET 2.0提供了哪些儲存SessionID的模式呢!
(2)、Cookie,有時也以其複數形式Cookies,指某些網站為了辨別使用者身分、進行session追蹤而儲存在使用者本地端上的資料(通常經過加密)。
三、解
1.asp.net環境下
在Global.asax檔中,寫如下程式碼:
void Application_BeginRequest(object sender, EventArgs e) { 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);//重新设定请求中的cookie值,将服务器端的session值赋值给它 }
/*---------------------------Aspx頁面端程式碼-------------- -------------------*/
this.hfAuth.Value = Request.Cookies[FormsAuthentication.FormsCookieName] == null ? string.Empty : Request.Cookies[FormsAuthentication.FormsCookieName].Value; this.hfAspSessID.Value = Session.SessionID;
將session值及驗證值儲存到客戶端控制中,然後你就可以透過js取得這兩個值,然後傳給下面的插件js初始化程式。
(之所以選擇將session值放入到控制中存儲,也是怕客戶端禁用cookie的考慮。)
/*-----------------------------以下是js程式碼------------ ----------------------*/
InitUpload: function(auth, AspSessID) { $("#uploadify").uploadify({ uploader: 'Scripts/jqueryplugins/Infrastructure/uploadify.swf', script: 'Handlers/ResourceHandler.ashx?OpType=UploadResource', cancelImg: 'Scripts/jqueryplugins/Infrastructure/cancel.png', queueID: 'fileQueue', sizeLimit: '21480000000', wmode: 'transparent ', fileExt: '*.zip,*.jpg, *.rar,*.doc,*.docx,*.xls,*.xlsx,*.png,*.pptx,*.ppt,*.pdf,*.swf,*.txt', auto: false, multi: true, scriptData: { ASPSESSID: AspSessID, AUTHID: auth },
...........//更多設定項,您可以檢視官方設定文件
在插件初始化的時候,將本地記錄下來的session值,以及身份驗證值傳給初始化方法,進行參數賦值,這樣,每次異步請求上傳文件的時候,相應的session值就包含在請求文件中了。
2.C#環境下
以上是asp.net下的解決方法,那麼C#中該如何處理呢?
我是這樣解決的,這樣所有上傳檔案的程式碼都不需要修改,改動量最小,但是有安全隱患:
if (this.LoginInfo == null) { // 解决uploadify兼容火狐谷歌浏览器上传问题 // 但是,此代码使系统有安全隐患,Flash程序请求该系统不需要验证 // 要解决此安全隐患,需要Flash程序传用户名和密码过来验证,但是该用户名和密码不能写在前端以便被不法用户看到 if (Request.UserAgent == "Shockwave Flash") { return; } else { filterContext.Result = RedirectToAction("LoginAgain", "Account", new { Area = "Auth" }); return; } }
我們的系統是ASP.NET MVC的,雖說透過加密的方式可以讓使用者看不到敏感訊息,但惡意使用者不需要把敏感資訊解密出來就可繞過系統驗證。
驗證訊息不能直接寫前台,可以用ajax從後台取得驗證訊息,然後傳給flash,然後在攔截器中驗證。
修改後:
JS代碼:
ajax請後台取得使用者名,傳給flash
$(function () { $.ajax({ url: "/Auth/Account/GetUserNamePwd", type: "POST", dataType: "json", data: {}, success: function (data) { $("#uploadify").uploadify({ height: 25, width: 100, swf: '/Content/Plugins/UploadifyJs/uploadify.swf', uploader: 'UploadFile', formData: { userName: data.data.userName, //ajax获取的用户名 pwd: data.data.pwd //ajax获取的密码 }, buttonText: '选择文件上传', fileSizeLimit: '4MB', fileTypeDesc: '文件', fileTypeExts: '*.*', queueID: 'fileQueue', multi: true, onUploadSuccess: function (fileObj, data, response) { var d = eval("(" + data + ")"); $(".uploadify-queue-item").find(".data").html(" 上传完成"); $("#url").val(d.url); $("#name").val(d.name); }, onUploadError: function (event, ID, fileObj, errorObj) { if (event.size > 4 * 1024 * 1024) { alert('超过文件上传大小限制(4M)!'); return; } alert('上传失败'); } }); //end uploadify } }); }); //end $
拦截器中代码:
...... if (this.LoginInfo == null) { // 解决uploadify兼容火狐谷歌浏览器上传问题 // 但是,此代码使系统有安全隐患,Flash程序请求该系统不需要验证 // 要解决此安全隐患,需要Flash程序传用户名和密码过来验证,但是该用户名和密码不能写在前端以便被不法用户看到 if (Request.UserAgent == "Shockwave Flash") { string userName = Request.Params["userName"]; string pwd = Request.Params["pwd"]; if (!string.IsNullOrWhiteSpace(userName) && !string.IsNullOrWhiteSpace(pwd)) { AuthDAL authDAL = new AuthDAL(); sys_user user = authDAL.GetUserInfoByName(userName); if (user != null && user.password == pwd) { return; } } } else { filterContext.Result = RedirectToAction("LoginAgain", "Account", new { Area = "Auth" }); return; } } ......
3.jsp版解决方法
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <% String syscontext = request.getContextPath(); %> <% String path = request.getContextPath(); String basePath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + path; String sessionid = session.getId(); %> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <link rel="stylesheet" type="text/css" href="<%=syscontext %>/webcontent/resourceManage/wallpapaer/uploadify/uploadify.css" /> <script type="text/javascript" src="http://code.jquery.com/jquery-1.7.2.min.js"></script> <script type="text/javascript" src="<%=syscontext %>/webcontent/resourceManage/wallpapaer/uploadify/jquery.uploadify-3.1.min.js"></script> <!-- 注意我使用的jquery uploadify版本--> <script type="text/javascript"> //用来计算上传成功的图片数 var successCount = 1; $(function() { var uploadUrl = '<%=basePath%>/uploadresource.do;jsessionid=<%=sessionid%>?Func=uploadwallpaper2Dfs'; var swfUrl2 = "<%=basePath%>/webcontent/resourceManage/wallpapaer/uploadify/uploadify.swf"; $('#file_upload').uploadify({ 'swf' : swfUrl2, 'uploader' : uploadUrl, // Put your options here 'removeCompleted' : false, 'auto' : false, 'method' : 'post', 'onUploadSuccess' : function(file, data, response) { add2SuccessTable(data); } }); }); /** * 将成功上传的图片展示出来 */ function add2SuccessTable(data){ var jsonObj = JSON.parse(data); for(var i =0; i < jsonObj.length; i++){ var oneObj = jsonObj[i]; var fileName = oneObj.fileName; var imgUrl = oneObj.imgUrl; var td_FileName = "<td>"+fileName+"</td>"; var td_imgUrl = "<td><img width='150' src='"+imgUrl+"'></img></td>"; var oper = "<td><input type='button' value='删除' onclick='deleteRow("+successCount+")'/></td>"; var tr = "<tr id='row"+successCount+"'>"+successCount+td_FileName+td_imgUrl+oper+"</tr>"; $("#successTable").append(tr); successCount++; } } function deleteRow(i){ $("#row"+i).empty(); $("#row"+i).remove(); } </script> <title>Insert title here</title> </head> <body> <input type="file" name="file_upload" id="file_upload" /> <p> <a href="javascript:$('#file_upload').uploadify('upload','*')">开始上传</a> <a href="javascript:$('#file_upload').uploadify('cancel', '*')">取消所有上传</a> </p> <table id="successTable"> <tr> <td>文件名</td> <td>图片</td> <td>操作</td> </tr> </table> </body> </html>
总结
简单的说,最终的解决办法就是可以在每个引用的文件后面加个随机数,让它每次请求都带个参数,该问题则自动解决