HTML5 postMessage+iframe實現檔案跨域非同步上傳
阿新 • • 發佈:2019-02-15
前段時間因為專案需求,要實現圖片的跨域上傳,研究了一番後實現了這個功能,這裡做個記錄方便日後遇到同樣的問題,也給後來者做個參考。
目前為止我瞭解到的檔案非同步上傳的方式有以下幾種
- flash控制元件 (IOS已經不支援flash了)
- HTML5 FormData
- iframe形式
當然我們還可以通過使用一些第三方的外掛來實現跨域上傳比如jQuery的ajaxFileUpload,不過好像也是通過構建iframe來實現非同步上傳的。通過form的target屬性將返回結果顯示在一個隱藏的iframe來實現類似ajax的效果,而且form表單的提交是可以跨域的。
以下是檔案上傳的html:
<!DOCTYPE html> <html> <head> <title>Html5 postMessage+iframe跨域上傳檔案</title> <meta charset='UTF-8'> <link rel="stylesheet" href="style.css"/> <script type="text/javascript" src="http://code.jquery.com/jquery-1.7.2.js"></script> </head> <body> <form class="form w_12" action="" method="post" enctype="multipart/form-data" target="uploadimg_ifm"> <div class="form-group w_12"> <label class="label fl w_12 tl"> 圖片上傳:</label> <div class="fr w_12"> <label class="btn-primary btn w_12" for="img">選擇圖片</label> <input type="file" id="img" accept="image/*" style="display:none" class="w_8" name="img"> <input type="hidden" class="imgurl" value=""> <div id="uploader-demo"> <!--用來存放item--> <div id="fileList" class="uploader-list"></div> </div> </div> </div> </form> <iframe name="uploadimg_ifm" style="display:none;"></iframe> <script src="jqthumb.min.js"></script> </body> </html>
加入js程式碼實現圖片預覽
var origin = "http://localhost:8088"; var host = "http://localhost:8088/fileupload/"; $("#img").change(function(){ var file = this.files[0]; //選擇上傳的檔案 var r = new FileReader(); r.readAsDataURL(file); //Base64 $(r).load(function(){ var $li = $( '<div class="file-item thumbnail">' + '<img src="'+ this.result +'" alt="" />' + '<div class="info">' + file.name + '</div>' + '</div>' ); $('#fileList').html( $li ); $('#fileList img').jqthumb(); //立即上傳圖片 $(".form").attr("action",host+"servlet/FileUploadServlet").submit(); }); });
重點來了 加入postMessage訊息監聽 顯示上傳結果
window.addEventListener("message", function( event ) {
if(event.origin != origin){
return false;
}
var data = event.data;
if (data.result == "success") {
$(".imgurl").val(data.url);
$('<div class="success">上傳成功</div>').appendTo( "#fileList .file-item" );
}else if (data.result == "failed") {
$('<div class="error">上傳失敗</div>').appendTo( "#fileList .file-item" );
}
}, false);
後臺這裡採用cos上傳元件
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
PrintWriter out = resp.getWriter();
String filePath = getServletContext().getRealPath("/") + "upload";
System.out.println(filePath);
File uploadPath = new File(filePath);
// 檢查資料夾是否存在 不存在 建立一個
if (!uploadPath.exists()) {
uploadPath.mkdir();
}
// 檔名
String fileName = "";
// 上傳檔案數
int fileCount = 0;
// 上傳檔案
MultipartRequest multipartRequest = new MultipartRequest(req, filePath, maxPostSize, encoding, fileRenamePolicy);//取得上傳檔案
Enumeration files = multipartRequest.getFileNames();
while (files.hasMoreElements()) {
String name = (String) files.nextElement();
fileName = multipartRequest.getFilesystemName(name);
String contentType = multipartRequest.getContentType(name);
fileCount = (fileName != null) ? ++fileCount : fileCount;
System.out.println("檔名:" + fileName);
System.out.println("檔案型別: " + contentType);
}
System.out.println("共上傳" + fileCount + "個檔案!");
String data = "";
if (fileCount >= 1) {
data = "{\"result\":\"success\",\"url\":\"upload/"+fileName+"\"}";
//返回執行js,呼叫HTML5 postmessage通知父框架上傳結果 第二個引數為接收訊息的物件視窗的 URL 地址,可以在 URL地址字串中使用萬用字元'*'指定全部。
out.print("<script>var iframeWin = parent.window;iframeWin.postMessage("+data+", \"*\");</script>");
}else{
data = "{\"result\":\"failed\",\"url\":\"\"}";
out.print("<script>var iframeWin = parent.window;iframeWin.postMessage("+data+", \"*\");</script>");
}
}
效果圖:
好了,以上就是主要實現的程式碼,並附上完整版下載連結fileupload.rar。如有不足之處還請留言指正…