zoukankan      html  css  js  c++  java
  • UEditor+七牛,实现图片直连上传

    最近做的项目,涉及到使用富文本编辑器,我选择了百度的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,然后在里面使用表单上传。

    此处可以参看官方文档关于表单上传请求跨域问题的解释,我暂时也没有时间深入研究。

  • 相关阅读:
    Android 之 Intent(意图)
    初识 Android
    SSM + VUE 实现简单的 CRUD
    VueUI -- iView4.0简单使用
    axios解决跨域问题(vue-cli3.0)
    Mybatis 逆向工程
    获取input type=file 的文件内容(纯文本)
    vue常见问题处理 -- 页面刷新时,如何保持原有vuex中的state信息
    mysql安装、使用 -- windows
    vue关于mock的简单使用
  • 原文地址:https://www.cnblogs.com/xtmp/p/6834383.html
Copyright © 2011-2022 走看看