首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Java 異步文件上傳三大方案深度對比:插件、隱藏 iframe 與 XMLHttpRequest Level 2

     編輯:Java 相關知識

三大方案總覽

方案核心原理瀏覽器兼容交互體驗進度控制實現難度
第三方插件Flash/ActiveX 底層 API需安裝插件優秀完全可控高(底層開發)
隱藏 iframeform target 指向 iframe,頁面不跳轉極佳(IE6+)一般(無進度)不可控低
XHR Level 2FormData + XMLHttpRequest 原生異步IE10+、現代瀏覽器極佳(實時進度、可取消)完全可控中

方案一:第三方插件(Flash/ActiveX)

利用插件繞過瀏覽器沙箱,直接訪問文件系統、控制上傳流程。優勢:大文件分片、斷點續傳、多線程並發、圖片預覽壓縮均可在客戶端完成。劣勢:用戶需安裝插件、移動端不支持、安全性受質疑、維護成本高。現已淘汰,不再展開。

方案二:隱藏 iframe 模擬異步(經典兼容方案)

核心機制

  1. <form target="iframeName"> 目標指向隱藏 <iframe name="iframeName">;
  2. 表單提交後,響應在 iframe 中渲染,主頁面不刷新;
  3. 服務端返回 <script>window.parent.callback(data)</script> 調用主頁面 JS 通知結果。

前端代碼

<iframe name="frm" style="display:none;"></iframe>
<form action="/upload2" method="post" enctype="multipart/form-data" target="frm" onsubmit="loading(true);">
    <input type="file" name="myfile">
    <input type="submit" value="異步上傳">
    <span id="uptxt">正在上傳...</span>
</form>
<div id="flist"></div>

<script>
function uploadFinished(fileName) {
    addToFlist(fileName);
    loading(false);
}
function addToFlist(fname) {
    $("#flist").append("<p id='" + fname + "'>" + fname + " <button onclick='delFile(\"" + fname + "\")'>刪除</button></p>");
}
function loading(show) {
    $("#uptxt").toggle(show);
}
</script>

服務端

// Node.js/Express 示例
router.post('/upload2', multipartMiddleware, (req, res) => {
    const fname = path.basename(req.files.myfile.path);
    setTimeout(() => { // 模擬處理延遲
        res.send(`<script>window.parent.uploadFinished('${fname}');</script>`);
    }, 3000);
});

優缺點

  • ✅ 兼容性極佳,無需插件;
  • ❌ 無上傳進度、無法取消、錯誤處理困難、交互體驗差;
  • ❌ 安全性:跨域受限,需同域或配置 document.domain。

方案三:XMLHttpRequest Level 2 真·異步上傳(現代標準)

核心 API

  • FormData:鍵值對構建 multipart/form-data,append('file', fileInput.files[0]);
  • XMLHttpRequest.upload.onprogress:上傳進度事件(loaded/total);
  • xhr.onloadstart/load/error/abort/loadend:完整生命週期事件;
  • xhr.abort():取消上傳。

完整前端實現

<input type="file" id="myfile">
<button onclick="upload()">異步上傳</button>
<span id="upprog"></span>
<button id="stopbtn" style="display:none">停止上傳</button>
<div id="flist"></div>

<script>
function upload() {
    const fd = new FormData();
    fd.append("myfile", $("#myfile")[0].files[0]);
    
    const xhr = new XMLHttpRequest();
    
    // 進度
    xhr.upload.onprogress = e => {
        if (e.lengthComputable) {
            const pct = Math.round(e.loaded * 100 / e.total);
            $("#upprog").text(pct + '%');
        }
    };
    
    // 開始
    xhr.onloadstart = () => {
        $("#upprog").text('開始上傳');
        $("#stopbtn").show().one('click', () => xhr.abort());
        loading(true);
    };
    
    // 成功
    xhr.onload = () => {
        $("#upprog").text('上傳成功');
        const ret = JSON.parse(xhr.responseText);
        addToFlist(ret.fname);
    };
    
    // 失敗/取消/結束
    xhr.onerror = () => $("#upprog").text('錯誤');
    xhr.onabort = () => $("#upprog").text('已取消');
    xhr.onloadend = () => loading(false);
    
    xhr.open('POST', '/upload3', true);
    xhr.send(fd);
}

function loading(show) {
    $("#uptxt, #stopbtn").toggle(show);
}

服務端響應 JSON

router.post('/upload3', multipartMiddleware, (req, res) => {
    const fname = path.basename(req.files.myfile.path);
    res.json({ fname }); // 返回文件名供前端展示
});

六大進度事件詳解

  1. loadstart:接收到首字節;
  2. progress:持續觸發,計算進度;
  3. error:網絡/服務端錯誤;
  4. abort:調用 abort() 取消;
  5. load:完整接收響應;
  6. loadend:無論成敗最終觸發。

方案選型建議

場景推薦方案理由
企業內網、老舊瀏覽器(IE8/9)隱藏 iframe零依賴、兼容性最好
現代 Web 應用、移動端 H5XHR Level 2 / Fetch API原生支持、體驗最佳、可進度/取消
大文件、斷點續傳、圖片客戶端壓縮WebUploader / Uppy / 自研分片基於 XHR2/Fetch 封裝,功能豐富
歷史系統維護、最小改動iframe 方案不改動服務端接口,快速接入

總結

從「插件霸權」到「iframe 變通」再到「XHR2 原生」,文件上傳技術演進折射出 Web 標準的成熟。現代項目首選 XHR Level 2(或 Fetch API),配合 FormData 實現原生異步、進度可視、可取消的優秀體驗。舊系統維護可用 iframe 方案過渡。理解 iframe 方案的「目標導向 + 跨幀通信」思想,更能啟發解決其他跨域、無刷新場景的靈感。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved