如何修复此跨域ActionScript 3错误?

soa*_*gem 6 flash urlrequest urlloader cross-domain actionscript-3

我将尽可能具体和冗长,并包括我正在使用的一些代码.我已经进行了搜索,发现了这个问题,看似相似; 但是作者使用的是ActionScript 2而不是3,而我似乎无法有效地应用任何给出我自己情况的答案.

我试图通过Flash/ActionScript 3模拟(以有限的方式)JavaScript的XMLHttpRequest对象的行为,以克服相同的域限制.但我发现ActionScript在这方面有其自身的局限性.我承认我可能会弄错,但据我所知,理论上仍然可以使用ActionScript进行这种跨域脚本编写,只要你获得所有权限.那就是我遇到麻烦的地方.

首先,我为一个名为AjaxRequest的类借用了一些开源代码,我将其保存为/ajax/AjaxRequest.as.然后我创建了一个名为/jsajax.fla导出到最终SWF文件的Flash文件/jsajax.swf.现在,这是包含Flash文件的第一个也是唯一一个框架的ActionScript代码:

import ajax.AjaxRequest;
Security.allowDomain("domainone.com");
Security.allowDomain("domaintwo.com");

function jsAjax(stringURL:String, stringMethod:String, stringData:String):void
{
    var xhr:AjaxRequest = new AjaxRequest(stringURL);
    xhr.contentType = "application/x-www-form-urlencoded";
    xhr.dataFormat = URLLoaderDataFormat.TEXT;

    if ( stringMethod.toUpperCase() == "POST" ) {
        xhr.method = URLRequestMethod.POST;
    } else {
        xhr.method = URLRequestMethod.GET;
    }

    xhr.addEventListener("complete", jsAjaxResponse);
    xhr.send(stringData);
    return;
}

function jsAjaxResponse(evt:Event):void
{
    ExternalInterface.call("jsAjaxResponse", evt.currentTarget.data.toString());
    return;
}

ExternalInterface.addCallback("jsAjax", jsAjax);
ExternalInterface.call("jsAjaxReady");
Run Code Online (Sandbox Code Playgroud)

到现在为止还挺好.我觉得Security.allowDomain不需要这些调用中的一个或多个,但他们试图解决这个问题是我的(不成功)尝试.

在我的JavaScript,我已经得到了定义了三个功能:jsAjax,jsAjaxResponse,和jsAjaxReady.最后一个是一个非常基本的函数,用于指示Flash对象成功加载(仅在加载时立即调用一次),而另外两个用于发送和接收数据.如您所见,它们具有相应的ActionScript对应物.

最后,我创建了一个简单的HTML页面/test.html,它嵌入了这个SWF文件(使用swfobject),并有几个简单的表单控件来调用该jsAjax函数.我的所有JavaScript定义也都嵌入在这个HTML文件中.我还创建了一个非常简单的PHP脚本/test.php,它打印出$_REQUEST数组的内容.这是我打算使用这个ajax方法请求的脚本.

我测试了三种情况,但我只能让其中两种工作:


情景一:所有在一台服务器上
如果我将所有这些文件上传到domainone.com,然后请求test.php,它运行正常.我的文件/文件夹结构如下所示:

domainone.com/jsajax.swf
domainone.com/test.html
domainone.com/test.php
Run Code Online (Sandbox Code Playgroud)

再次,这是有效的.jsAjaxResponse函数接收来自test.php的数据就好了.


场景二:在两台服务器上,向左倾斜
当我将HTML和SWF上传到第一台服务器,然后让它在第二台服务器上调用PHP脚本时,它就不能立即工作了.我做了一些挖掘,发现通过crossdomain.xml在domaintwo.com上创建了一个授予domainone.com访问权限的文件,这就修复了它.所以我的文件/文件夹结构如下所示:

domainone.com/jsajax.swf
domainone.com/test.html
domaintwo.com/test.php
domaintwo.com/crossdomain.xml
Run Code Online (Sandbox Code Playgroud)

在crossdomain.xml文件中明确允许domainone.com时,可行.同样,jsAjaxResponse函数接收来自test.php的数据就好了.


情景三:在两台服务器上,向右倾斜
当我将除了HTML之外的所有内容上传到domaintwo.com时,我再也无法让它工作了.换句话说,domainone.com上的HTML引用了托管在domaintwo.com上的SWF文件,该SWF文件正在尝试向domaintwo.com发出请求.为了以防万一,我从场景2中保留了相同的crossdomain.xml文件.我的文件/文件夹结构如下所示:

domainone.com/test.html
domaintwo.com/jsajax.swf
domaintwo.com/test.php
domaintwo.com/crossdomain.xml
Run Code Online (Sandbox Code Playgroud)

这是我唯一无法工作的情况,这就是我需要开始工作的情况.前两个实际上只是测试场景,看看脚本是否正常工作.当我尝试在这里运行我的jsAjax函数时,我最终会在Firebug中出现两次错误:

uncaught exception: Error calling method on NPObject! [plugin exception: Error in Actionscript. Use a try/catch block to find error.].
uncaught exception: Error calling method on NPObject! [plugin exception: Error in Actionscript. Use a try/catch block to find error.].
Run Code Online (Sandbox Code Playgroud)

救命!如何在场景3中使用它?

soa*_*gem 4

我刚刚想通了!它确实与我的 Flash 文件中的命令有关Security.allowDomain。我实际上是在domainone.com 的子域上托管它test.html,这让它失败了。它必须是完全匹配、子域等等。事实证明,我不需要Security.allowDomain引用 domaintwo.com 的命令,也不需要crossdomain.xml场景 3 中存在该文件!

由于在我最终使用的此脚本的“真实”版本中,我不一定知道 domainone.com 实际上是什么,因此我将 Flash 文件顶部的代码更改为:

import ajax.AjaxRequest;
try {
    var domain1:String = LoaderInfo(this.root.loaderInfo).parameters["allow"];
    if ( domain1.length > 0 ) {
        Security.allowDomain(domain1);
    }
} catch (error:Error) { }
try {
    var domain2:String = LoaderInfo(this.root.loaderInfo).parameters["allowhttps"];
    if ( domain2.length > 0 ) {
        Security.allowInsecureDomain(domain2);
    }
} catch (error:Error) { }
...
Run Code Online (Sandbox Code Playgroud)

然后,在我用来嵌入 SWF 的 JavaScript 中,我基本上从 获取页面的当前域document.location.toString(),检查它是否使用 http 或 https,然后将域传递到 asallow和/allowhttps或flashvars 参数。可能有一种“更好”的方法来做到这一点,不依赖于在 Flash Vars 中显式设置域(从 Flash 内部进行某种自动检测),但我对 ActionScript 不够熟悉,无法弄清楚这一点出去。由于这个文件已经在 J​​avaScript 和 ActionScript 之间进行了大量的双向通信,所以这并不是什么大不了的事情。这个解决方案对我来说已经足够好了。