使用Editor.md画像アップロードの問題と解決策

使用Editor.md画像アップロードの問題と解決策

春ブーツ2.2.4.RELEASE

問題と解決策

情報:前と後のプロジェクトでは、クロスドメインを含む、分離の終わりです。

ファイルが保存されるフォルダの試料を用いた試験では、例Editor.md「画像upload.html」を提供しました。

「ローカルアップロード」ボタンをクリックして、画像やアップロードを選択し、サーバは画像を受け取ることができます。

画像が正常にアップロードし、正しいデータをサーバー側応答した場合、通常の状況下では、その後、追加の画像ダイアログ絵アドレスが大幅にサーバーのURLに背中を返却する必要があります。

私は成功した写真をアップロードするときただし、クライアント(ブラウザ)は、セキュリティエラープロンプトが表示され、「例外SecurityErrorを:許可は、アクセスプロパティに拒否された」ドキュメント「ONクロスオリジンのオブジェクト以下のように、」:
ここに画像を挿入説明

する旨の「クロスオリジン・オブジェクトの」ドキュメント:「アクセス許可のアクセスプロパティに拒否されたとSecurityError」メッセージが表示されたら、推測「クロスオリジンのオブジェクトは、」「クロスは、ソースオブジェクト、」その後で、「ソースオブジェクト間のアクセスを持っていません。」

画像dialog.jsファイルを開き、ライン164を探し、してみてくださいここで見ることができます:

var body = (uploadIframe.contentWindow ? uploadIframe.contentWindow : uploadIframe.contentDocument).document.body;

コードの文字通りの意味から、それは推測取るべきであるdocumentのをbody

Aはファジービット?ああ、又は第一uploadIframe.contentWindowおよびuploadIframe.contentDocumentコンソールに出力し、彼らが何であるかを参照してください。修正画像dialog.jsファイルとして、次のとおりです。

if(log) { // 自定义的变量,var log = true;。如果后期处于调试阶段,又不想打印这些信息,将其设置 false 即可。
    console.log("uploadIframe.contentWindow", uploadIframe.contentWindow);
    console.log("uploadIframe.contentDocument", uploadIframe.contentDocument);
}
var body = (uploadIframe.contentWindow ? uploadIframe.contentWindow : uploadIframe.contentDocument).document.body;

修正後は、意図的にプロンプ​​トをトリガ、再び完全なとブラウザに保存され、アップロードの写真です:
ここに画像を挿入説明

少し手がかりは、uploadIframe.contentDocumentされnull、その後、我々は最初にそれに注意を払うことができません。

再看看 uploadIframe.contentWindow 指向一个 Window,且 URL 指向服务器端的上传接口,刚好也是 image-upload.html 文件中 editormd 配置的 imageUploadURL 参数值:

var testEditor = editormd("test-editormd", {
    ... // 其他配置
    imageUpload : true,
    imageFormats : ["jpg", "jpeg", "gif", "png", "bmp", "webp"],
    imageUploadURL : "http://localhost:8080/attachment/image/upload",
    
    ...
});

通过选取页面中的元素发现,以上提到 URL 刚好和图片上传的表单 action 一样:
ここに画像を挿入説明

由此猜想,上文提及的安全错误“SecurityError: Permission denied to access property “document” on cross-origin object”是由于 image-dialog.js 文件中的代码尝试访问图片上传的表单中的元素导致的:
ここに画像を挿入説明

通过查看 image-dialog.js 文件中的源码,可以发现 submitHandler 函数(第 1 ~ 18 行)绑定在 type="submit" 对象(暂时这么称呼,此处描述不准确)的点击事件(第 20 行):

var submitHandler = function() {

    ...

    uploadIframe.onload = function() {
        ...
        
        if(log) {
            console.log("uploadIframe.contentWindow", uploadIframe.contentWindow);
            console.log("uploadIframe.contentDocument", uploadIframe.contentDocument);
        }
        var body = (uploadIframe.contentWindow ? uploadIframe.contentWindow : uploadIframe.contentDocument).document.body;

        ...

        return false;
    };
};

dialog.find("[type=\"submit\"]").bind("click", submitHandler).trigger("click");

猜想 dialog.find("[type=\"submit\"]") 是一个提交按钮,可能是添加图片对话框中的本地上传按钮,因为当我们点击本地上传之后,就触发安全错误,而该错误又是执行 (uploadIframe.contentWindow ? uploadIframe.contentWindow : uploadIframe.contentDocument).document.body; 导致的,见以上 代码的第 12 行。

我们验证一下,修改 image-dialog.js 文件,看看 dialog.find("[type=\"submit\"]") 是什么:

if (log) {
    console.log('dialog.find("[type=\"submit\"]")', dialog.find("[type=\"submit\"]"));
}
dialog.find("[type=\"submit\"]").bind("click", submitHandler).trigger("click");

再次上传图片,可以看到 dialog.find("[type=\"submit\"]") 返回的对象确实和本地上传按钮有关系!
ここに画像を挿入説明

根据 dialog.find("[type=\"submit\"]") 提供的线索,继续查看 image-dialog.js 文件,发现 type="submit"本地上传按钮,即有可能是在这块代码定义:

var dialogContent = ( (settings.imageUpload) ? "<form action=\"" + action +"\" target=\"" + iframeName + "\" method=\"post\" enctype=\"multipart/form-data\" class=\"" + classPrefix + "form\">" : "<div class=\"" + classPrefix + "form\">" ) +
                        ( (settings.imageUpload) ? "<iframe name=\"" + iframeName + "\" id=\"" + iframeName + "\" guid=\"" + guid + "\"></iframe>" : "" ) +
                        "<label>" + imageLang.url + "</label>" +
                        "<input type=\"text\" data-url />" + (function(){
                            return (settings.imageUpload) ? "<div class=\"" + classPrefix + "file-input\">" +
                                                                "<input type=\"file\" name=\"" + classPrefix + "image-file\" accept=\"image/*\" />" +
                                                                "<input type=\"submit\" value=\"" + imageLang.uploadButton + "\" />" +
                                                            "</div>" : "";
                        })() +
                        "<br/>" +
                        "<label>" + imageLang.alt + "</label>" +
                        "<input type=\"text\" value=\"" + selection + "\" data-alt />" +
                        "<br/>" +
                        "<label>" + imageLang.link + "</label>" +
                        "<input type=\"text\" value=\"http://\" data-link />" +
                        "<br/>" +
                    ( (settings.imageUpload) ? "</form>" : "</div>");

请耐心看一下代码,此处有两个关键点:

  1. <form> 元素的 action 属性,见第 1 行。
  2. 第 7 行,<input> 元素的类型(type)是 submit。现在它的 value 是未知的。

我们可以看看这两者是什么,修改 image-dialog.js 文件,将它们打印到控制台(第 1 ~ 4 行):

if (log) {
    console.log("action: ", action);
    console.log("imageLang.uploadButton: ", imageLang.uploadButton);
}
var dialogContent = ( (settings.imageUpload) ? "<form action=\"" + action +"\" ... +
... // 其它,省略

从控制台的输出,我们可以看到,action 对应服务器的上传接口,而 imageLang.uploadButton,即上文提到的 <input> 元素的 value 值,刚好对应添加图片对话框的本地上传按钮:
ここに画像を挿入説明

我们通过选取页面中的元素,可以看到图片上传表单的 action本地上传提交按钮与上面提到的信息刚好吻合:
ここに画像を挿入説明

由此,可以推测 var dialogContent = ( (settings.imageUpload) ? "<form action=\"" + action + ... ); 主要功能是创建图片上传表单。

由于图片上传表单的 action 与 image-dialog.js 文件不同源,导致 image-dialog.js 文件中的代码不能访问图片上传表单的元素。

那么,该如何解决安全错误呢?

嗯,不妨使用 AJAX 代替表单提交功能。

如果使用 AJAX 上传图片,就不需要设置图片上传表单的 action,因此,我们可以注释 editormd 配置中的 imageUploadURL 属性:

var testEditor = editormd("test-editormd", {
    ...
    imageUpload : true,
    imageFormats : ["jpg", "jpeg", "gif", "png", "bmp", "webp"],
    // imageUploadURL : "http://localhost:8080/attachment/image/upload",
    
    ...
});

这样,添加图片表单 action 就变成这样子:
ここに画像を挿入説明

上图中的添加图片表单 action 中的 guid 是一个时间戳,其在 image-dialog.js 文件中定义:

if (editor.find("." + dialogName).length < 1)
{
    var guid   = (new Date).getTime();
    var action = settings.imageUploadURL + (settings.imageUploadURL.indexOf("?") >= 0 ? "&" : "?") + "guid=" + guid;

    ...
}

或者,我们可以直接修改 image-dialog.js 文件中 action 变量,将其置空(第 8 行):

if (editor.find("." + dialogName).length < 1)
{
    var guid   = (new Date).getTime();
    var action = settings.imageUploadURL + (settings.imageUploadURL.indexOf("?") >= 0 ? "&" : "?") + "guid=" + guid;

    ...

    action = "";
    var dialogContent = ( (settings.imageUpload) ? "<form action=\"" + action + "\" ...
}

清除了表单的 action 属性之后,我们需要禁用本地上传的提交功能。修改 image-dialog.js 文件,在 submitHandler 函数中的末尾添加 return false;,并关闭加载效果:

var submitHandler = function() {
    var uploadIframe = document.getElementById(iframeName);
    
    uploadIframe.onload = function() {
        ...
    };
    loading(false); // 关闭加载效果
    return false;
};

现在,通过本地上传按钮选择一张图片并打开,是不会将图片上传至服务器。

接下来,让我们看看 uploadIframe.onload 干了什么。这里有三个关键信息:

  1. 第 8 行的 json.success
  2. 第 9 行的 json.url
  3. 第 12 行的 json.message
var submitHandler = function() {
    ...
    
    uploadIframe.onload = function() {
        ...

        if(!settings.crossDomainUpload) {
          if (json.success === 1) { // 上传成功
              dialog.find("[data-url]").val(json.url);
          }
          else {
              alert(json.message);
          }
        }

        return false;
    };
    
    loading(false); // 关闭加载效果
    return false;
};

这三个关键信息,刚好对应 image-upload.html 示例中提到的 JSON 数据格式(第 8 ~ 13 行):

var testEditor = editormd("test-editormd", {
    ...
    imageUpload : true,
    imageFormats : ["jpg", "jpeg", "gif", "png", "bmp", "webp"],
    // imageUploadURL : "http://localhost:8080/attachment/image/upload",
    
    /*
     上传的后台只需要返回一个 JSON 数据,结构如下:
     {
        success : 0 | 1,           // 0 表示上传失败,1 表示上传成功
        message : "提示的信息,上传成功或上传失败及错误信息等。",
        url     : "图片地址"        // 上传成功时才返回
     }
     */
});

回到 image-dialog.js 文件中的 submitHandler 函数,让我们看看 dialog.find("[data-url]") 是什么,将其打印到控制台(第 3 行):

var submitHandler = function() {
    if(log) {
        console.log('dialog.find("[data-url]")', dialog.find("[data-url]"));
    }
    
    ...

    loading(false); // 关闭加载效果
    return false;
};

可以看到,dialog.find("[data-url]") 对应图片地址
ここに画像を挿入説明

だから、dialog.find("[data-url]").val(json.url);役割がある-画像が正常にアップロードする場合、サーバーが返すURLフィルの追加写真ダイアログ画像アドレス(9行目):

var submitHandler = function() {
    ...
    
    uploadIframe.onload = function() {
        ...

        if(!settings.crossDomainUpload) {
          if (json.success === 1) { // 上传成功
              dialog.find("[data-url]").val(json.url);
          }
          else {
              alert(json.message);
          }
        }

        return false;
    };
    
    loading(false); // 关闭加载效果
    return false;
};

場合はこれまでのところ、上記の分析ほとんど憶測。次に、私たちは確認してみましょう。修正画像dialog.jsファイルsubmitHandler機能、およびコメントuploadIframe.onload関連するコード:

var submitHandler = function() {
    
    // var uploadIframe = document.getElementById(iframeName);
    
    // uploadIframe.onload = function() {

    //     loading(false);
        
    //     var body = (uploadIframe.contentWindow ? uploadIframe.contentWindow : uploadIframe.contentDocument).document.body;
    //     var json = (body.innerText) ? body.innerText : ( (body.textContent) ? body.textContent : null);

    //     json = (typeof JSON.parse !== "undefined") ? JSON.parse(json) : eval("(" + json + ")");

    //     if(!settings.crossDomainUpload)
    //     {
    //       if (json.success === 1)
    //       {
    //           dialog.find("[data-url]").val(json.url);
    //       }
    //       else
    //       {
    //           alert(json.message);
    //       }
    //     }

    //     return false;
    // };
    
    loading(false); // 关闭加载效果
    return false;
};

AJAXのアップロードの写真を使用します:

var submitHandler = function() {
    var form = dialog.find("[enctype=\"multipart/form-data\"]")[0];
    var formData = new FormData(form);
    
    $.ajax({
        type: 'post',
        // url: "http://localhost:8080/attachment/image/upload", // 你的服务器端的图片上传接口。如果你设置了 imageUploadURL,那么可以使用下面的方式
        url: settings.imageUploadURL + (settings.imageUploadURL.indexOf("?") >= 0 ? "&" : "?") + "guid=" + guid,
        data: formData,
        cache: false,
        processData: false,
        contentType: false,
        success: function(data, textStatus, jqXHR) {
            // console.log(data);
            // console.log(textStatus);
            // console.log(jqXHR);
            if (data.success === 1) { // 上传成功
                dialog.find("[data-url]").val(data.url); // 设置图片地址
            }
            else {
                alert(data.message); // 上传失败,弹出警告信息
            }
        },
        error: function(XMLHttpRequest, textStatus, errorThrown) {
            // console.log(XMLHttpRequest);
            // console.log(textStatus);
            // console.log(errorThrown);
        }
    });
    
    loading(false); // 关闭加载效果
    return false;
};

我々が正常に画像をアップロードする場合さて、あなたは絵アドレスを見ることができます:
ここに画像を挿入説明

クリックして、[OK]のボタンを、絵も値下げエディタに対応することができます。
ここに画像を挿入説明

参照

オンラインEditor.mdオープンソースのMarkdownエディタ

春ブーツ - AJAXクロスドメインの画像のアップロード

公開された55元の記事 ウォンの賞賛0 ビュー3178

おすすめ

転載: blog.csdn.net/qq_29761395/article/details/104194166