標籤:成功 複雜 mda doc 圖片路徑 個人 over cross img
最近做的項目,涉及到使用富文字編輯器,我選擇了百度的UEditor。同時,我們的圖片放在七牛雲端儲存上。關於這兩者間的整合,我寫下一些個人的經驗,與大家分享。
圖片上傳方案
目前來說,Web端基於七牛等雲端儲存的圖片上傳方式分為以下兩種:
1. 上傳圖片至服務端,再將資料轉寄至七牛。
通過服務端接受使用者上傳的內容,同時可以對內容進行有效性審核,拒絕不合規範的內容,然後從服務端將內容上傳至七牛。
這種方法可以有效控制並記錄使用者提交的內容,但同時也增加了伺服器的運行壓力。
2. 直接上傳圖片至七牛,然後通知服務端。
消除了伺服器頻寬瓶頸的制約,利用CDN的優勢大大提高了上傳速度,同時利用七牛的Callback和魔法變數等特性,擷取上傳圖片的基礎資訊。
很明顯,第二種方案可以大大最佳化上傳過程中的體驗,同時也減輕了自有伺服器的運行壓力。
本文接下來將描述如何通過修改UEditor,來實現圖片的直連上傳。
服務端實現
服務端需要實現兩個介面,分別是UEditor配置下發 和 七牛上傳令牌下發。
1. UEditor配置下發
這部分沒什麼複雜的東西,就是把UEditor的設定檔按照要求放在服務端,具體方法可以參見後端部署說明以及原始碼中ASP.NET部分的樣本。
除此以外,配置中還要修改以下內容
/* 上傳圖片配置項 */ "imageUrl": "http://up.qiniu.com/", "imageActionName": "uploadimage", /* 執行上傳圖片的action名稱 */ "imageFieldName": "file", /* 提交的圖片表單名稱 */ "imageMaxSize": 2048000, /* 上傳大小限制,單位B */ "imageAllowFiles": [ ".jpg", ".jpeg" ], /* 上傳圖片格式顯示 */ "imageCompressEnable": true, /* 是否壓縮圖片,預設是true */ "imageCompressBorder": 1600, /* 圖片壓縮最長邊限制 */ "imageInsertAlign": "none", /* 插入的圖片浮動方式 */ "imageUrlPrefix": "http://7xkcdc.com2.z0.glb.qiniucdn.com/", /* 圖片訪問路徑首碼 */ "imagePathFormat": "upload/image/{yyyy}{mm}{dd}/{time}{rand:6}", /* 上傳儲存路徑,可以自訂儲存路徑和檔案名稱格式 */
imageUrl: 這裡直接填寫七牛上傳服務的地址
imageUrlPrefix: 圖片路徑的首碼
2. 七牛上傳令牌(Token)下發
根據七牛的Form上傳模型,用戶端每次在上傳圖片之前,都需要擷取該次上傳事務中所用到上傳令牌(token)。由於令牌的產生安全要求比較高,因此被設計成在服務端實現。
此處可以使用七牛提供的C#SDK加快開發效率。
var key = MakeKey(); //產生key var ret = new { url = "$(key)", key = "$(key)", w = "$(imageInfo.width)", h = "$(imageInfo.height)", state = "SUCCESS" }; var policy = new PutPolicy(Bucket) { SaveKey = key, ReturnBody = JsonConvert.SerializeObject(ret) }; return policy.Token();這裡需要注意兩點
1. 根據UEditor二次開發後端請求規範,UEditor需要在上傳成功後服務端返回state和url欄位,即:需要七牛返回以上欄位。
2. 針對第1點需求,我們利用了自訂內容響應(ReturnBody)以及魔法變數,自訂我們需要返回給用戶端的欄位資訊。
修改UEditor代碼以下是上傳流程的基本思路
1. 編輯器初始化,並從服務端擷取配置資訊
2. 開始上傳前,從服務端擷取七牛令牌,並附加到上傳的請求中
3. 上傳圖片至七牛伺服器
首先,我們來分析一下,UEditor使用中哪些情境會涉及到圖片上傳?
總結下來則分別是:單圖上傳,多圖上傳(圖片管理器),直接把圖片拖進編輯器上傳。
我們先從多圖上傳(圖片管理器)講起。
1. 圖片管理器上傳
圖片管理器的代碼主要集中在dialogs/image/image.js
可以看到在編輯器初始化的時候有這樣一段定義,其中actionUrl即上傳伺服器位址。
其中editor.getOpt(‘imageActionName‘)即表示從配置中讀取imageActionName,查看服務端配置後得知該值被配置為"uploadimage"
很明顯,這邊是做了配置的集中化管理,因此我們找到ueditor/ueditor.all.js(可能低版本的ueditor在_src/core/Editor.js中修改)並做修改,將涉及上傳動作情境的請求地址均改為imageUrl,即七牛服務地址。
getActionUrl: function(action) { var actionName = this.getOpt(action) || action, imageUrl = this.getOpt(‘imageUrl‘), serverUrl = this.getOpt(‘serverUrl‘);/*加上紅色代碼*/ if (action == "uploadimage") { return imageUrl; } if (!serverUrl && imageUrl) { serverUrl = imageUrl.replace(/^(.*[\/]).+([\.].+)$/, ‘$1controller$2‘); } if (serverUrl) { serverUrl = serverUrl + (serverUrl.indexOf(‘?‘) == -1 ? ‘?‘ : ‘&‘) + ‘action=‘ + (actionName || ‘‘); return utils.formatUrl(serverUrl); } else { return ‘‘; } }
接下來我們回到dialogs/image/image.js,找到上傳開始前的事件,此處附加上從服務端擷取的七牛token,注意ajax是同步調用的。此處將jquery通過ajax擷取token,並放在data["token"]中
2. 圖片拖進編輯器上傳
這部分代碼主要集中在ueditor/ueditor.all.js(舊版路徑_src/plugins/autoupload.js)
此處又看到了上傳路徑的配置,由於之前我們已經統一改過路徑擷取的代碼了,所以這部分可以跳過
找到其執行上傳的部分,與之前類似地附上擷取token的代碼 加入紅色代碼
/* 建立Ajax並提交 */
var xhr = new XMLHttpRequest(),
fd = new FormData(),
params = utils.serializeParam(me.queryCommandValue(‘serverparam‘)) || ‘‘,
url = utils.formatUrl(actionUrl + (actionUrl.indexOf(‘?‘) == -1 ? ‘?‘:‘&‘) + params);
fd.append(fieldName, file, file.name || (‘blob.‘ + file.type.substr(‘image/‘.length)));
fd.append(‘type‘, ‘ajax‘);
$.ajax({
dataType:"json",
async:false,
url:"../upload/token",
success:function(res){
fd.append("token",res.token);
}
});
xhr.open("post", url, true);
xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest");
3. 單圖上傳
看似最簡單的功能,其實留了個跨域的坑。我翻看了單圖上傳的代碼,發現它的實現方法是建了個iframe,然後在裡面使用表單上傳。
此處可以參看官方文檔關於表單上傳請求跨域問題的解釋,我暫時也沒有時間深入研究。
UEditor+七牛,實現圖片直連上傳