Как исправить эту междоменную ошибку ActionScript 3? - PullRequest
6 голосов
/ 28 октября 2009

Я собираюсь быть настолько конкретным и подробным, насколько это возможно, и включать в себя часть кода, который я использую. Я уже сделал поиск и нашел этот вопрос , который кажется похожим; однако автор там использовал ActionScript 2 вместо 3, и я не мог эффективно применить какой-либо из ответов, данных к моей собственной ситуации.

Я пытаюсь (ограниченным образом) эмулировать поведение объекта JavaScript XMLHttpRequest через Flash / ActionScript 3, чтобы преодолеть ограничение того же домена. Но я обнаружил, что ActionScript имеет свои ограничения в этом отношении. Я допускаю, что могу ошибаться, но из того, что я понимаю, теоретически все еще возможно выполнять такого рода междоменные сценарии с использованием ActionScript, при условии, что вы получаете все права. И вот тут у меня проблемы.

Сначала я позаимствовал некоторый открытый исходный код для класса с именем AjaxRequest , который я сохранил как /ajax/AjaxRequest.as. Затем я создал Flash-файл с именем /jsajax.fla, который экспортирует в окончательный SWF-файл /jsajax.swf. Теперь вот код ActionScript, который содержит первый и единственный кадр файла Flash:

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 определены три функции: 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

Опять же, это работает . Функция 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

Если явно разрешить domainone.com в файле crossdomain.xml, это работает . Опять же, функция jsAjaxResponse прекрасно возвращает данные из test.php.


СЦЕНАРИЙ ТРИ: На обоих серверах наклон вправо
Когда я загрузил все, кроме HTML, на domaintwo.com, я больше не мог заставить его работать. Другими словами, HTML на domainone.com ссылается на SWF-файл, размещенный на domaintwo.com, и этот SWF-файл пытается отправить запрос на domaintwo.com. Я оставил тот же файл crossdomain.xml из сценария 2, на всякий случай. Моя структура файлов / папок выглядела так:

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?

1 Ответ

4 голосов
/ 28 октября 2009

Я только что понял это! Это было связано с командами 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) { }
...

Затем в JavaScript, который я использую для встраивания туда SWF, я в основном извлекаю текущий домен страницы из document.location.toString(), проверяю, использует ли он http или https, а затем передаю домен в как allow и / или allowhttps в параметре flashvars. Возможно, существует «лучший» способ сделать это, не основанный на явной настройке домена во Flash Vars (своего рода автоматическое обнаружение из Flash), но я недостаточно разбираюсь в ActionScript, чтобы понять, что из. И так как этот файл уже выполняет целую кучу двунаправленной связи между JavaScript и ActionScript, это не такая уж большая проблема. Это решение достаточно хорошо для меня.

...