6

我将尽可能具体和详细,并包含我正在使用的一些代码。我已经进行了搜索,发现了这个问题,看起来很相似;但是那里的作者使用的是 ActionScript 2 而不是 3,我似乎无法有效地将任何答案应用于我自己的情况。

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

首先,我为一个名为AjaxRequest的类借用了一些开源代码,我将其保存为/ajax/AjaxRequest.as. 然后我创建了一个名为的 Flash 文件/jsajax.fla,该文件导出到最终的 SWF 文件,/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");

到现在为止还挺好。我觉得Security.allowDomain不需要一个或多个这样的电话,但它们是我试图解决这个问题的(不成功的)尝试。

在我的 JavaScript 中,我定义了三个函数:jsAjaxjsAjaxResponsejsAjaxReady. 最后一个只是一个非常基本的函数,用于指示 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

同样,这有效。jsAjaxResponse 函数接收来自 test.php 的数据就好了。


场景二:在两台服务器上,向左倾斜
当我将 HTML 和 SWF 上传到第一台服务器,然后让它调用第二台服务器上的 PHP 脚本时,它并没有立即工作。我做了一些挖掘,发现通过在 domaintwo.com 上创建一个crossdomain.xml文件来授予对 domainone.com 的访问权限,这解决了它。所以我的文件/文件夹结构看起来像这样:

domainone.com/jsajax.swf
domainone.com/test.html
domaintwo.com/test.php
domaintwo.com/crossdomain.xml

当在 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

这是我唯一无法工作的情况,也是我需要工作的情况。前两个实际上只是测试场景,以查看脚本是否正常工作。当我尝试在这里运行我的 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.].

帮助!如何让它在场景 3 中工作?

4

1 回答 1

4

我刚刚想通了!它确实与Security.allowDomain我的 Flash 文件中的命令有关。我实际上是test.html在 domainone.com 的一个子域上托管它,而那是把它扔掉了。它必须是完全匹配的,子域和所有。事实证明,我不需要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) { }
...

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

于 2009-10-28T20:16:27.127 回答