主题: v3.5跨域上传图片的解决方案和遗留问题
作者: 等钱中, 发布日期: 2010-11-08 15:40:37, 浏览数: 8127

最近的项目,博文在b1.a.com,图片在p1.a.com

 

参考网上跨域的解决方案,本来以为把plugin下几个静态页的document.domain都修改为a.com就ok了,

但是很快就发现只有firefox和chrome正常,

ie几个版本下都提示Access is Denied,

调试后发现是弹出的对话框就开始挂掉了

原来在ie下面,编辑器自身这个动态生成的iframe的document.domain还是b1.a.com,而不是a.com

 

后来用的一个比较笨的proxy方法,利用iframe和location.hash

1、先在b1.a.com建立静态页call_back.html

上传对话框在/js/kindeditor/plugins/image/image.html,可以放在同一目录
比如:/js/kindeditor/plugins/image/call_back.html

2、然后在p1.a.com上传完成是的动态生成一个iframe指向这个call_back.html,图片的url信息编码附在后面

3、然后修改js代码,让他在上传时,编辑面页上传后就监听image.html的location.hash变化,如果15秒还不能上传,监听退出


虽然p1.a.com生成的代码不能操作image.html的location.hash,但是call_back.html同域,可以操作,这样问题就解决了

 

 

call_back.html代码如下

<html><head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>ie shit</title>
<script type="text/javascript">
var upload_callback = function(){
    var data = location.hash ? location.hash.substring(1):'';
    parent.parent.location.hash=data;
};
</script>
</head>
<body onload="upload_callback();">
</body></html>

 

p1.a.com上传完成输出:

<html><head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>PIC UPLOAD</title>
<script type="text/javascript">
    var upload_callback = function(){
        var iframe_proxy = document.createElement('iframe');
        iframe_proxy.style.display = 'none';
        iframe_proxy.src = 'http://b1.a.com/js/kindeditor/plugins/image/call_back.html#'+encodeURIComponent('{_$RESULT_JSON_}');
        document.body.appendChild(iframe_proxy);
    };
</script>
</head>
<body onload="upload_callback();">

</body></html>

 

大概修改的kindeditor.js代码是onloadFunc的内容,在line:3874

//for fucking  ie
var _tmp = dialogDoc.location;
var onloadFunc = function() {
    try{KE.util.showLoadingPage(id);}catch(e) {;}
    KE.event.remove(uploadIframe, 'load', onloadFunc);
    var wait_upload_count = 0;
    var wait_upload =setInterval(function(){
        if(wait_upload_count>0){
            try{
                var data = _tmp.hash ? _tmp.hash.substring(1):'';
                if('' != data){
                    data = decodeURIComponent(data);
                    data = eval('('+data+')');
                    clearInterval(wait_upload);
                    KE.util.hideLoadingPage(id);
                    if (typeof data === 'object' && 'error' in data) {
                        if (data.error === 0) {
                            self.insert(id, data.url, title, width, height, 0, align);
                        } else {
                            alert(data.message);
                            return false;
                        }
                    }
                }
                if(wait_upload_count == 15){
                    window.clearInterval(wait_upload);
                    KE.util.hideLoadingPage(id);
                    return false;
                }
            }
            catch(e) {;}
        }
        try{KE.util.showLoadingPage(id);}catch(e) {;}
        wait_upload_count ++;
    }, 1000);
};

 

 

遗留问题

1、大家发现这个 dialogDoc其实就是kindeditor/plugins/image/image.html的句柄

为什么加一个,var _tmp = dialogDoc.location;

这就是诡异的问题1:

不在onloadFunc 外面操作一下找变量存放dialogDoc.location

firefox不能捕捉这个变量,ie却可以

 

2、大家有疑问为什么用了几个:try{KE.util.showLoadingPage(id);}catch(e) {;}

主要是一确定上传,

firefox下那个loading框出现一会就马上就消失了,ie却正常保持到上传结束

这就是为什么我用这个多showLoadingPage来盖住面页

这是我的问题2,

 

期待高手帮我解答一下

谢谢!

 

另外注意,上述我的方法在js中使用了eval,参数是传递的,容易造成安全漏洞

 

 

 

作者: Roddy, 发布日期: 2010-11-08 16:12:07

上传还是通过中转服务器上传到图片服务器比较好。

 

编辑器在abc.com,上传图片时先上传到abc.com的临时目录,abc.com通过程序将图片移动到photo.abc.com,这样做可以支持多台图片服务器,实现负载平衡和备份。

回复
作者: 等钱中, 发布日期: 2010-11-08 17:25:38

Re二楼

这种方案可以研究一下。不过会存在2个问题:


1,直接在前端服务器上传和处理图片,会占用较多的流量和内存,而且服务器职责不明确

2,编辑器的图片需要实时预览,如果使用中转,保存文章时需要把文章的图片链接做正则替换处理,如果后台图片无法同步,生成的文章页的图片还不能马上看到,步骤麻烦很多,问题也多.


仅表个人意见

回复
作者: Roddy, 发布日期: 2010-11-08 18:14:08

可以先等待同步结束后写入DB,同一个局域网里网速很快,一般图片顶多几百KB,完全可以忽略这方面的延迟。

前端服务器也可以不生成实际文件,但好像PHP必须生成临时文件,其它语言可以直接将内存里的图片数据发送到图片服务器。

PS:我以前公司是拥有几千万用户的SNS网站,也是用这个方法,根本不是性能瓶颈。

回复
作者: 等钱中, 发布日期: 2010-11-11 10:57:14
谢谢赐教
回复
发表新帖 发表回复