Extjs文件上传 - 跨域帧

7

我在我的Extjs应用程序中有一个文件上传字段。我正在尝试使用以下代码将文件加载到服务器:

var form = Ext.getCmp('ProcImpNewSugFileForm').getForm();
var fileNameStr = Ext.getCmp('ProcImpNewSugFileUpload').getValue().split("\\");
if(fileNameStr){
var filename = fileNameStr[fileNameStr.length-1];
if(form.isValid()){
    form.submit({
        url: '/PISRFileUploader.php',            
        waitMsg: 'Uploading your file...',                
        success: function (formPanel, action, result) {
            Ext.Msg.alert('Msg',"Success: "+action.response.responseText);
        },
        failure: function (formPanel, action, result) {
            Ext.Msg.alert('Msg',"Failure: "+action.response.responseText);
        }
    });
   }
}

但是当我尝试上传任何文件时,文件会被加载到服务器上,但是响应是这样的:

    Failure: {success:false,message:"Blocked a frame with origin 'http://localhost' from accessing a cross-origin frame."}

Thanks in Advance!

3个回答

4

这是由Uberdude在Sencha论坛中发现的一个Ext js错误。

问题描述:

当您使用包含要上传的文件输入的表单进行Ext.Ajax.request,或手动将isUpload选项设置为true时,而不是以正确的Ajax请求方式提交表单,Ext会以标准HTML方式将其提交到动态生成的隐藏iframe。然后从iframe中读取json响应体以创建伪造的Ajax响应。如果进行上传Ajax请求的页面已更改其document.domain属性,例如,home.example.com的页面包括来自static.example.com的资源,它希望在不违反浏览器的同源策略的情况下使用javascript进行操作,因此两者都将其document.domain设置为"example.com"。如果home.example.com然后对home.example.com服务器上的URL进行上传Ajax请求,则写入响应的iframe将其document.domain设置为"home.example.com"。因此,当home.example.com上的Ajax.request中的ExtJS代码尝试从iframe中提取文档正文时,它将被同源策略阻止,并且传递给回调函数的响应将不正确地具有空的responseText。

解决方法: 1. 在上传请求时将document.domain传递给服务器。 2. 在服务器响应中,在响应文本/HTML中添加document.domain。

response.setHeader('Content-Type', 'text/html'); response.write('document.domain = "' + params.__domain + '";'); response.write(JSON.stringify({msg: '欢迎 ' + params.name})); response.end('');

详情:

请参考: http://www.sencha.com/forum/showthread.php?136092-Response-lost-from-upload-Ajax-request-to-iframe-if-document.domain-changed


1

为Wilk的回答增加额外的评论。

如果您的主机和目标端口不同,请使用以下解决方案。

index.html文件中,在头部下面使用以下行:

<script type=text/javascript>document.domain =document.domain;</script>

在您的响应中,需要包含头信息Content-Type:'text/html'和响应内容。

'<html><head><script type=text/javascript>document.domain =document.domain;</script></head><body>{success: true}</body></html>'

此处硬编码了成功消息,您可以根据输入使用任何自定义消息。

谢谢, Santrupta


1
这是cheftao的答案的改进。
如果您需要使用不同的域名(例如本地主机与不同端口),请按照以下步骤操作:
在客户端,在提交表单之前,更新文档域并随后使用表单数据提交它。
  document.domain = document.domain;
  myForm.submit({
    params: {
      domain: document.domain
    },
    ...
  });

在服务器端,以content-type为text/html的方式响应,并使用以下字符串(此示例使用ExpressJS):
var domain = req.body.domain,
    script = '<script type="text/javascript">document.domain = "' + domain + '";</script>',
    body = '<body>' + JSON.stringify({success: true}) + '</body>';

res.send('<html><head>' + script + '</head>' + body + '</html>');

更新:2016年5月19日

实际上,最好的解决方案是使用反向代理,避免这种问题的发生。


“反向代理”是什么意思?你有相关链接吗? - harryBundles

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接