傳統 `` 需整頁 PostBack,體驗差。SWFUpload 利用 Flash 繞過瀏覽器限制,提供:
注意:Flash 已停止支援,現代專案建議改用 HTML5 File API + FormData + XMLHttpRequest/fetch 或成熟套件(Fine Uploader, Uppy, Dropzone.js)。本文保留為維護舊專案參考。
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="ChangeAvatar.aspx.cs" Inherits="NovelChannel.ChangeAvatar" %>
<!DOCTYPE html>
<html xmlns="https://www.w3.org/1999/xhtml">
<head runat="server">
<title>大頭貼上傳</title>
<link href="/CSS/jQueryUI/jquery-ui-1.10.2.custom.css" rel="stylesheet" />
<script src="/JS/jQuery/jquery-1.9.1.js"></script>
<script src="/JS/jQuery/jquery-ui-1.10.2.custom.js"></script>
<script src="/JS/swf/swfupload.js"></script>
<script src="/JS/swf/handlers.js"></script>
<style>
#avatarContainer { width:200px; height:300px; border:1px solid #ccc; background-size:cover; background-position:center; }
#draggable { width:50px; height:50px; background:transparent; border:1px solid #000; cursor:move; }
</style>
</head>
<body>
<form id="form1" runat="server">
<span id="btnUploadImgPlaceholder"></span>
<div id="divFileProgressContainer"></div>
<br />
<div id="avatarContainer">
<div id="draggable">拖曳</div>
</div>
<img id="imgAvatar" style="display:none;" />
</form>
<script type="text/javascript">
// 1. 上傳成功回呼:解析 JSON,更新預覽區
function uploadImgSuccess(file, response) {
var data = $.parseJSON(response); // [path, width, height]
$("#avatarContainer").css({
"background-image": "url(" + data[0] + ")",
"width": data[1] + "px",
"height": data[2] + "px"
});
}
$(function () {
// 2. 初始化 SWFUpload
var swfu = new SWFUpload({
// 後端設定
upload_url: "/Ajax/UploadAvatar.ashx",
post_params: { "ASPSESSID": "<%=Session.SessionID %>" }, // 傳遞 Session ID 維持登入狀態
// 檔案限制
file_size_limit: "2 MB",
file_types: "*.jpg",
file_types_description: "JPG Images",
file_upload_limit: 0,
// 事件處理器(定義於 handlers.js)
swfupload_preload_handler: preLoad,
swfupload_load_failed_handler: loadFailed,
file_queue_error_handler: fileQueueError,
file_dialog_complete_handler: fileDialogComplete,
upload_progress_handler: uploadProgress,
upload_error_handler: uploadError,
upload_success_handler: uploadImgSuccess,
upload_complete_handler: uploadComplete,
// 按鈕外觀
button_image_url: "/JS/swf/images/XPButtonNoText_160x22.png",
button_placeholder_id: "btnUploadImgPlaceholder",
button_width: 160,
button_height: 22,
button_text: '<span class="button">選擇圖片(最大2MB)</span>',
button_text_style: '.button { font-family: Helvetica, Arial, sans-serif; font-size: 14pt; }',
button_text_top_padding: 1,
button_text_left_padding: 5,
// Flash 檔案路徑
flash_url: "/JS/swf/swfupload.swf",
flash9_url: "/JS/swf/swfupload_FP9.swf",
custom_settings: { upload_target: "divFileProgressContainer" },
debug: false
});
});
// 3. jQuery UI 拖曳(示範用,非上傳核心)
$(function () {
$("#draggable").draggable({ containment: "parent", cursor: "crosshair" });
$("#draggable").dblclick(function () {
var pos = $(this).position();
alert("相對座標: " + pos.left + ", " + pos.top);
});
});
</script>
</body>
</html>
using System;
using System.IO;
using System.Drawing;
using System.Web;
using System.Web.Script.Serialization;
namespace NovelChannel.Ajax
{
public class UploadAvatar : IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
context.Response.ContentType = "text/plain";
HttpPostedFile file = context.Request.Files["FileData"]; // SWFUpload 固定欄位名
if (file == null || file.ContentLength == 0)
{
context.Response.Write("未收到檔案");
return;
}
// 1. 驗證副檔名
string ext = Path.GetExtension(file.FileName).ToLower();
if (ext != ".jpg" && ext != ".jpeg")
{
context.Response.Write("只允許 JPG 格式");
return;
}
// 2. 產生唯一檔名
string fileName = DateTime.Now.ToString("yyMMddHHmmss") + new Random().Next(1000, 9999) + ".jpg";
string relPath = "/Images/UserImg/" + fileName;
string fullPath = context.Server.MapPath("~" + relPath);
// 3. 確保目錄存在
Directory.CreateDirectory(Path.GetDirectoryName(fullPath));
// 4. 儲存原檔
file.SaveAs(fullPath);
// 5. 讀取圖片尺寸回傳 JSON
using (Image img = Image.FromFile(fullPath))
{
var result = new string[] { relPath, img.Width.ToString(), img.Height.ToString() };
var json = new JavaScriptSerializer().Serialize(result);
context.Response.Write(json);
}
}
public bool IsReusable => false;
}
}
// 檔案加入佇列後自動開始上傳
function fileDialogComplete(numFilesSelected, numFilesQueued) {
if (numFilesQueued > 0) this.startUpload();
}
// 上傳進度條更新
function uploadProgress(file, bytesLoaded, bytesTotal) {
var percent = Math.ceil((bytesLoaded / bytesTotal) * 100);
$("#divFileProgressContainer").html("上傳中: " + percent + "%");
}
// 上傳失敗處理
function uploadError(file, errorCode, message) {
alert("上傳失敗: " + message);
$("#divFileProgressContainer").html("失敗");
}
// 上傳完成(無論成敗)清理佇列
function uploadComplete(file) {
if (this.getStats().files_queued > 0) this.startUpload();
}
| 項目 | 說明 |
|---|---|
| Session 傳遞 | SWFUpload 另開請求不自動帶 Cookie,需手動傳 ASPSESSID,後端 context.Request.Cookies["ASP.NET_SessionId"] 讀取 |
| 檔案欄位名 | SWFUpload 固定上傳欄位為 FileData,後端 Request.Files["FileData"] 取得 |
| 跨域/信任 | Flash 需 crossdomain.xml 或同網域部署 |
| 錯誤代碼 | 參考 SWFUpload 文檔:SWFUpload.QUEUE_ERROR.*, SWFUpload.UPLOAD_ERROR.* |
// HTML5 + FormData + fetch 範例
const input = document.querySelector('#fileInput');
input.addEventListener('change', async (e) => {
const file = e.target.files[0];
const formData = new FormData();
formData.append('file', file);
const res = await fetch('/api/upload', { method: 'POST', body: formData });
const data = await res.json();
// 更新預覽...
});
優點:無外掛相依、原生支援進度、行動裝置相容、安全性高。