UEditor 是百度開源的富文本編輯器,.NET 版本透過 Uploader.ashx 處理上傳。本文涵蓋:專案整合步驟、前端初始化、後端配置、上傳路徑自訂、安全性設定、常見坑點,適用於 ASP.NET WebForms 與 MVC。
YourProject/ ├── Ueditor/ # 編輯器核心資源 │ ├── editor_all.js │ ├── editor_config.js │ ├── themes/default/ueditor.css │ ├── net/ │ │ ├── Uploader.cs # 核心上傳處理 │ │ └── Config/ # 配置類別 │ ├── fileUp.ashx # 檔案上傳端點 │ ├── imageUp.ashx # 圖片上傳端點 │ ├── scrawlUp.ashx # 塗鴉上傳端點 │ └── ...其他 .ashx ├── Uploads/ # 上傳儲存目錄(需寫入權限) │ ├── image/ │ ├── file/ │ └── video/ └── Web.config / appsettings.json
<!-- 1. 引入樣式與腳本 -->
<link href="Ueditor/themes/default/ueditor.css" rel="stylesheet" />
<script src="Ueditor/editor_config.js"></script>
<script src="Ueditor/editor_all.js"></script>
<!-- 2. 編輯器容器(建議 textarea)-->
<textarea id="txtContent" name="txtContent" runat="server" style="width:100%;height:400px;">
<p>初始內容...</p>
</textarea>
<!-- 3. 實例化 -->
<script type="text/javascript">
// 方式 A:傳統實例化 (UEditor 1.2.4+)
var ue = UE.getEditor('txtContent', {
initialFrameWidth: '100%',
initialFrameHeight: 400,
toolbars: [[
'fullscreen', 'source', '|', 'undo', 'redo', '|',
'bold', 'italic', 'underline', 'strikethrough', '|',
'forecolor', 'backcolor', '|',
'justifyleft', 'justifycenter', 'justifyright', '|',
'insertorderedlist', 'insertunorderedlist', '|',
'link', 'unlink', '|', 'image', 'video', 'attachment', '|',
'table', 'simpleupload'
]]
});
// 方式 B:簡化實例化 (自動綁定同 id textarea)
// UE.getEditor('txtContent');
</script>
<!-- 4. 提交按鈕 -->
<input type="submit" value="送出" />
textarea 原生支援表單提交,Request.Form["txtContent"] 直接取得 HTML 內容。div 需手動同步隱藏欄位,易遺漏導致後端取不到值。<script type="text/plain" id="editor">,但 .NET 版配合 textarea 最穩定。
// Ueditor/editor_config.js
window.UEDITOR_HOME_URL = "/Ueditor/"; // 網站根目錄下的 Ueditor 資料夾
window.UEDITOR_CONFIG = {
// 後端統一處理端點 (UEditor 1.4.3+ 採用單一 controller)
serverUrl: "/Ueditor/net/Uploader.ashx",
// 圖片上傳
imageActionName: "uploadimage",
imageFieldName: "upfile",
imageMaxSize: 2048000, // 2MB
imageAllowFiles: [".png", ".jpg", ".jpeg", ".gif", ".bmp", ".webp"],
imageCompressEnable: true,
imageCompressBorder: 1600,
imageInsertAlign: "none",
imageUrlPrefix: "", // 圖片 URL 前綴(如 CDN 域名)
imagePathFormat: "/Uploads/image/{yyyy}{mm}{dd}/{time}{rand:6}",
// 檔案上傳
fileActionName: "uploadfile",
fileFieldName: "upfile",
fileMaxSize: 51200000, // 50MB
fileAllowFiles: [".doc", ".docx", ".xls", ".xlsx", ".ppt", ".pptx", ".pdf", ".txt", ".zip", ".rar"],
filePathFormat: "/Uploads/file/{yyyy}{mm}{dd}/{time}{rand:6}",
// 視頻上傳
videoActionName: "uploadvideo",
videoMaxSize: 102400000, // 100MB
videoAllowFiles: [".mp4", ".webm", ".ogg", ".mov", ".avi"],
videoPathFormat: "/Uploads/video/{yyyy}{mm}{dd}/{time}{rand:6}",
// 涂鴉、線上圖片抓取等其他設定...
catcherActionName: "catchimage",
catcherMaxSize: 2048000,
catcherAllowFiles: [".png", ".jpg", ".jpeg", ".gif", ".bmp"],
catcherPathFormat: "/Uploads/image/{yyyy}{mm}{dd}/{time}{rand:6}",
// 列出圖片/檔案(用於插入圖片對話框)
imageManagerActionName: "listimage",
imageManagerListPath: "/Uploads/image/",
fileManagerActionName: "listfile",
fileManagerListPath: "/Uploads/file/"
};
<%@ WebHandler Language="C#" Class="Uploader" CodeBehind="Uploader.cs" %>
public class Uploader : IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
// 1. 讀取 action 參數決定處理類型
string action = context.Request["action"];
// 2. 依 action 分派:uploadimage, uploadfile, uploadvideo, listimage, catchimage...
switch (action)
{
case "uploadimage":
UploadImage(context); break;
case "uploadfile":
UploadFile(context); break;
// ...
}
}
private void UploadImage(HttpContext context)
{
var file = context.Request.Files["upfile"]; // 對應 imageFieldName
if (file == null || file.ContentLength == 0)
{
WriteResult(context, new { state = "ERROR", message = "無檔案" });
return;
}
// 3. 驗證副檔名、大小
string ext = Path.GetExtension(file.FileName).ToLower();
if (!Config.ImageAllowFiles.Contains(ext))
{
WriteResult(context, new { state = "ERROR", message = "不允許的檔案類型" });
return;
}
// 4. 產生儲存路徑(依 imagePathFormat 解析變數)
string savePath = PathFormatter.Format(Config.ImagePathFormat, ext);
string fullPath = context.Server.MapPath(savePath);
Directory.CreateDirectory(Path.GetDirectoryName(fullPath));
// 5. 儲存
file.SaveAs(fullPath);
// 6. 回傳 JSON (UEditor 要求格式)
WriteResult(context, new
{
state = "SUCCESS",
url = savePath, // 相對網站根目錄
title = Path.GetFileName(file.FileName),
original = Path.GetFileName(file.FileName)
});
}
private void WriteResult(HttpContext context, object result)
{
context.Response.ContentType = "application/json";
// 解決 IE9 以下下載 JSON 問題
string callback = context.Request["callback"];
string json = Newtonsoft.Json.JsonConvert.SerializeObject(result);
if (!string.IsNullOrEmpty(callback))
json = $"{callback}({json})";
context.Response.Write(json);
}
}
<configuration>
<system.web>
<!-- 允許大檔上傳 (預設 4MB) -->
<httpRuntime maxRequestLength="102400" requestValidationMode="2.0" /> <!-- 100MB -->
<pages validateRequest="false" /> <!-- 允許 HTML 內容提交 -->
</system.web>
<system.webServer>
<security>
<requestFiltering>
<requestLimits maxAllowedContentLength="104857600" /> <!-- 100MB (bytes) -->
</requestFiltering>
</security>
<handlers>
<add name="UEditorHandler" path="Ueditor/net/*.ashx" verb="*" type="System.Web.UI.SimpleHandlerFactory" />
</handlers>
</system.webServer>
</configuration>
protected void btnSubmit_Click(object sender, EventArgs e)
{
string htmlContent = txtContent.Value; // HtmlTextArea 控制項
// 或 Request.Form["txtContent"]
// 防 XSS:建議使用 HtmlSanitizer 過濾
var sanitizer = new HtmlSanitizer();
string safeHtml = sanitizer.Sanitize(htmlContent);
// 儲存至資料庫
ArticleService.Save(new Article { Content = safeHtml });
}
[HttpPost]
[ValidateInput(false)] // 允許 HTML 提交,配合 [AllowHtml] 屬性更精確
public ActionResult Create(ArticleViewModel model)
{
if (!ModelState.IsValid) return View(model);
var sanitizer = new HtmlSanitizer();
model.Content = sanitizer.Sanitize(model.Content);
_articleService.Create(model);
return RedirectToAction("Index");
}
public class ArticleViewModel
{
[AllowHtml] // 僅此屬性允許 HTML
public string Content { get; set; }
// ...
}
| 問題 | 原因 | 解決方案 |
|---|---|---|
| 上傳後圖片顯示 404 | imagePathFormat 路徑與實際虛擬目錄不符 |
確認 imageUrlPrefix + imagePathFormat 組合為正確 URL,瀏覽器開發者工具 Network 面板檢查請求 URL |
| IE9/10 上傳回應被下載而非解析 | 回應 Content-Type 為 application/json,IE 誤判 | Uploader.cs 中檢查 callback 參數輸出 JSONP,或設定 Response.ContentType = "text/html" |
| 大檔上傳失敗 (404/500) | maxRequestLength / maxAllowedContentLength 太小 |
調大 Web.config 兩處設定,並確認 IIS 應用程式集區限制 |
| 提交內容被截斷/編碼錯誤 | validateRequest="true" 阻擋 HTML |
頁面/控制器加 ValidateInput(false) 或 [AllowHtml],全域關閉風險較高 |
| 圖片上傳後編輯器不顯示 | 回傳 JSON 格式不符 UEditor 規範 | 必須包含 state: "SUCCESS", url, title, original 欄位 |
| 無法列出已上傳圖片 | imageManagerListPath 指向錯誤目錄 |
確認虛擬路徑對應實體目錄,且 IIS 有讀取權限 |
Content-Type、檔案簽名。{time}{rand:6} 避免覆蓋與猜測。HtmlSanitizer。Uploader.ashx 檢查用戶登入/角色,未授權回 401/403。UEditor .NET 版維護較少,新專案建議考慮:
POST /api/upload,後端回傳 {url: "..."},解耦最徹底。editor_config.js 設定 serverUrl、imagePathFormat、Web.config 放大上傳限制、Uploader.ashx 實作上傳邏輯並回傳標準 JSON。textarea + UE.getEditor('id'),後端用 Request.Form["id"] 取值。