zoukankan      html  css  js  c++  java
  • editormd 跨域上传图片的问题解决方式 以及 Uncaught DOMException: Blocked a frame with origin from accessing a cross-origin frame 报错的原因和解决方法

    editormd 解决 图片上传的问题的方式有点绕, 他的图片是通过表单方式提交,但是表单提交成功后会刷新页面,为了解决页面刷新的问题,editormd将表单提交的响应提交给了一个子 iframe标签,然后通过找到该iframe标签,获取该标签的body,得到内容,转换后复制给父窗口的相关标签.

    这样做通常是没问题的,同域上传不会出现问题,但是跨域上传的时候就会报错,如标题.

    因为浏览器有个同源策略,iframe本质上相当于一个新的页面,有自己的url地址,当父窗口要访问获取子窗口的内部数据时,如果两个窗口的域名不一致(域名,IP,端口任一不同),那么就会报出该安全错误.

    editormd提供了一个跨域上传的方案,就是配置时提供一个回传地址,我考虑的意思是,editormd将结果放在该会传地址中,该回调地址的域名与父窗口一致,那么就可以访问该iframe内部的数据了.

    但是可能因为我哪里没弄对,依然报错如上.

    所以我决定修改editormd的插件代码.

    原文件中相关代码如下: 构建代码部分

     1 var action = settings.imageUploadURL + (settings.imageUploadURL.indexOf("?") >= 0 ? "&" : "?") + "guid=" + guid;
     2 
     3                 if (settings.crossDomainUpload)
     4                 {
     5                     action += "&callback=" + settings.uploadCallbackURL + "&dialog_id=editormd-image-dialog-" + guid;
     6                 }
     7 
     8                 var dialogContent = ( (settings.imageUpload) ? "<form action="" + action +"" target="" + iframeName + "" method="post" enctype="multipart/form-data" class="" + classPrefix + "form">" : "<div class="" + classPrefix + "form">" ) +
     9                                         ( (settings.imageUpload) ? "<iframe name="" + iframeName + "" id="" + iframeName + "" guid="" + guid + ""></iframe>" : "" ) +
    10                                         "<label>" + imageLang.url + "</label>" +
    11                                         "<input type="text" data-url />" + (function(){
    12                                             return (settings.imageUpload) ? "<div class="" + classPrefix + "file-input">" +
    13                                                                                 "<input type="file" name="" + classPrefix + "image-file" accept="image/*" />" +
    14                                                                                 "<input type="submit" value="" + imageLang.uploadButton + "" />" +
    15                                                                             "</div>" : "";
    16                                         })() +
    17                                         "<br/>" +
    18                                         "<label>" + imageLang.alt + "</label>" +
    19                                         "<input type="text" value="" + selection + "" data-alt />" +
    20                                         "<br/>" +
    21                                         "<label>" + imageLang.link + "</label>" +
    22                                         "<input type="text" value="http://" data-link />" +
    23                                         "<br/>" +
    24                                     ( (settings.imageUpload) ? "</form>" : "</div>");

    8到15行为上传图片的代码,这部分代码首先出现的问题是csrftoken的问题, 表单提交需要在请求头或表单内添加csrftoken字段,这部分 editormd没有做好,除此之外其他部分可以看到传图的原理:

     <form action="" + action +"" target="" + iframeName + "" method="post" 可以看到是把新页面指向了子iframe(后面加上的),

    然后就是获取iframe内容的部分:

     1 var submitHandler = function() {
     2 
     3                         var uploadIframe = document.getElementById(iframeName);
     4 
     5                         uploadIframe.onload = function() {
     6 
     7                             loading(false);
     8 
     9                             var body = (uploadIframe.contentWindow ? uploadIframe.contentWindow : uploadIframe.contentDocument).document.body;
    10                             var json = (body.innerText) ? body.innerText : ( (body.textContent) ? body.textContent : null);
    11 
    12                             json = (typeof JSON.parse !== "undefined") ? JSON.parse(json) : eval("(" + json + ")");
    13 
    14                             if(!settings.crossDomainUpload)
    15                             {
    16                               if (json.success === 1)
    17                               {
    18                                   dialog.find("[data-url]").val(json.url);
    19                               }
    20                               else
    21                               {
    22                                   alert(json.message);
    23                               }
    24                             }
    25 
    26                             return false;
    27                         };
    28                     };

    这部分代码先获取iframe元素,然后得到内部文本,转换为object对象,判断响应状态,赋值给Input标签.

    问题就出在获取子iframe元素内容上,基于同源策略,浏览器不让获取.

    解决方法也很简单,但是同样花费了我一晚上加一上午的时间(主要是方向错了,前期主要精力放在解决iframe跨域的问题,发现不好解决,然后换了个思路,决定改变插件的传图方式为ajax)

    下面是修改后的代码(红色部分为修改的部分):

     1                 var CallBackJS = "<script>" +
     2                     "function mdUpload(file) {" +
     3                     "upload_file(file, function(pic, url) { json = {success:1,url:url,message:'OK'};document.getElementById('json-body-ht').innerText = JSON.stringify(json) })" +
     4                     " }" +
     5                     "</script>";
     6 
     7                 var dialogContent = ( (settings.imageUpload) ? "<form action="" + action +"" target="" + iframeName + "" method="post" enctype="multipart/form-data" class="" + classPrefix + "form">" : "<div class="" + classPrefix + "form">" ) +
     8                                         ( (settings.imageUpload) ? "<iframe name="" + iframeName + "" id="" + iframeName + "" guid="" + guid + ""></iframe>" : "" ) +
     9                                         "<label>" + imageLang.url + "</label>" +
    10                                         "<input type="text" data-url />" + (function(){
    11                                             return (settings.imageUpload) ? "<div class="" + classPrefix + "file-input">" +
    12                                                                                 "<pre id='json-body-ht' style='display: none'></pre>" +
    13                                                                                 "<input type='hidden' name='csrf_token' value='" + CSRFTOKEN + "' />" +
    14                                                                                 "<input onchange='mdUpload(this.files[0])' type="file" name="" + classPrefix + "image-file" accept="image/*" />" +
    15                                                                                 "<input type="submit" value="" + imageLang.uploadButton + "" />" +
    16                                                                             "</div>" + CallBackJS : "";
    17                                         })() +
    18                                         "<br/>" +
    19                                         "<label>" + imageLang.alt + "</label>" +
    20                                         "<input type="text" value="" + selection + "" data-alt />" +
    21                                         "<br/>" +
    22                                         "<label>" + imageLang.link + "</label>" +
    23                                         "<input type="text" value="http://" data-link />" +
    24                                         "<br/>" +
    25                                     ( (settings.imageUpload) ? "</form>" : "</div>");
     1 var submitHandler = function() {
     2 
     3                         var uploadIframe = document.getElementById(iframeName);
     4 
     5                         uploadIframe.onload = function() {
     6 
     7                             loading(false);
     8 
     9                             // var body = (uploadIframe.contentWindow ? uploadIframe.contentWindow : uploadIframe.contentDocument).document.body;
    10                             var body = document.getElementById('json-body-ht');
    11                             var json = (body.innerText) ? body.innerText : ( (body.textContent) ? body.textContent : null);
    12 
    13                             console.log(json);
    14                             json = (typeof JSON.parse !== "undefined") ? JSON.parse(json) : eval("(" + json + ")");
    15                             console.log(json.success, json.success === 1);
    16                             if(!settings.crossDomainUpload)
    17                             {
    18                               if (json.success === 1)
    19                               {
    20                                   dialog.find("[data-url]").val(json.url);
    21                               }
    22                               else
    23                               {
    24                                   alert(json.message);
    25                               }
    26                             }
    27 
    28                             return false;
    29                         };
    30                     };

    修改的部分主要四个地方:

    1. 添加csrftoken 这部分后面极可能会多余,临时只是解决插件自己的表单提交, 添加接受数据的元素
    2. 添加监听事件
    3. 添加回调函数
    4. 修改元素获取方式
    upload_file是我定义的全局上传图片方法,通过axios方式上传,参数为文件对象和回调,具体内部代码 略.
    主要操作是按照插件之前的规则将相应数据填充给自定义元素,自定义元素在父窗口中,直接调用不会出现跨域的问题
    将插件源代码中获取数据的方式从 iframe 获取 改为 自定义元素获取.

    我一个后端对前端的东西不是很懂,经验不足,前期花费大量时间在解决 iframe跨域上,所以有时候 方向 也很重要.
  • 相关阅读:
    Swing程序最佳架构设计—以业务对象为中心的MVC模式(转)
    股市投资策略总结(转)
    php学习笔记--高级教程--读取文件、创建文件、写入文件
    史上最简单的Hibernate入门简单介绍
    Java中StringBuilder的清空方法比較
    DHCP Option 60 的理解
    ICMP报文分析
    软件測试自学指南---从入门到精通
    Qt多线程学习:创建多线程
    Bulk Insert命令具体
  • 原文地址:https://www.cnblogs.com/haiton/p/11142666.html
Copyright © 2011-2022 走看看