Как передать "Null" (настоящую фамилию!) На веб-службу SOAP в ActionScript 3?

У нас есть сотрудник, чья фамилия Null. Приложение для поиска сотрудников убивается, когда эта фамилия используется в качестве условия поиска (что часто случается довольно часто). Полученная ошибка (спасибо Fiddler!):

  <soapenv:Fault>
   <faultcode>soapenv:Server.userException</faultcode>
   <faultstring>coldfusion.xml.rpc.CFCInvocationException: [coldfusion.runtime.MissingArgumentException : The SEARCHSTRING parameter to the getFacultyNames function is required but was not passed in.]</faultstring>

Симпатичный, да?

Тип параметра string.

Я использую:

  • WSDL (SOAP).
  • Flex 3.5
  • ActionScript 3
  • ColdFusion 8

Обратите внимание, что ошибка не возникает при вызове веб-службы как объекта со страницы ColdFusion.

Ответ 1

Отслеживание вниз

Сначала я думал, что это ошибка принуждения, в которой null принуждалось к "null" и проходил тест "null" == null. Не это. Я был близок, но так очень, очень неправильно. Извините за это!

С тех пор я сделал много прокручивание на wonderfl.net и прослеживая код в mx.rpc.xml.*. На строке 1795 XMLEncoder (в источнике 3.5) в setValue все XMLEncoding сводится к

currentChild.appendChild(xmlSpecialCharsFilter(Object(value)));

который по существу совпадает с:

currentChild.appendChild("null");

Этот код, согласно моей оригинальной скрипке, возвращает пустой элемент XML. Но почему?

Причина

По словам комментатора Justin Mclean о сообщении об ошибке FLEX-33664, следующий виновник (см. последние два теста в моем скрипта, которые подтверждают это):

var thisIsNotNull:XML = <root>null</root>;
if(thisIsNotNull == null){
    // always branches here, as (thisIsNotNull == null) strangely returns true
    // despite the fact that thisIsNotNull is a valid instance of type XML
}

Когда currentChild.appendChild передается строка "null", она сначала преобразует ее в корневой элемент XML с текстом null, а затем проверяет этот элемент на нулевом литерале. Это слабый тест на равенство, поэтому либо содержащий XML-символ принуждается к нулевому типу, либо нулевой тип принуждается к корневому элементу xml, содержащему строку "null", и тест проходит там, где он, возможно, должен завершиться ошибкой. Одно исправление может заключаться в том, чтобы всегда использовать строгое равенство при проверке XML (или что-нибудь, действительно) для "nullness."

Решение

Единственное разумное обходное решение, которое я могу придумать, не исправляя эту ошибку в каждой проклятой версии ActionScript, - это проверить поля для "null" и избежать их как значений CDATA.

Значения CDATA являются наиболее подходящим способом для изменения целочисленного текстового значения, которое в противном случае могло бы вызвать проблемы с кодированием/декодированием. Hex-кодирование, например, предназначено для отдельных символов. Значения CDATA предпочтительнее, если вы избегаете всего текста элемента. Самой большой причиной этого является то, что он поддерживает читаемость человека.

Ответ 2

На примечание xkcd, веб-сайт Bobby Tables имеет хорошие рекомендации по недопущению неправильной интерпретации пользовательских данных (в данном случае строки "Null" ) в SQL-запросах на разных языках, включая ColdFusion.

Неясно, что это источник проблемы, и учитывая решение, указанное в комментарии к первому ответу (вложение параметров в структуру), кажется вероятным, что это было что-то еще.

Ответ 3

Проблема может быть в коде Flex SOAP. Попробуйте расширить SOAP-кодировщик в приложении Flex и отладить программу, чтобы увидеть, как обрабатывается нулевое значение. Я предполагаю, что он прошел как NaN (не номер). Это когда-нибудь испортит процесс отмены сообщений SOAP (особенно в JBoss 5 server...). Я помню, как расширил SOAP-кодер и выполнил явную проверку того, как обрабатывается NaN.

(На стороне примечания, вы ожидаете сделать что-то полезное, если идентификатор сотрудника - Null, это не проблема проверки? Возможно, я ошибаюсь, так как я почти не знаю этого требования...)

Ответ 4

@doc_180 имел правильную концепцию, за исключением того, что он фокусировался на числах, тогда как исходный плакат имел проблемы со строками.

Решение состоит в изменении файла mx.rpc.xml.XMLEncoder. Это строка 121

    if (content != null)
        result += content;

[Я просмотрел SDK Flex 4.5.1; номера строк могут отличаться в других версиях]

В принципе, проверка не выполняется, потому что "контент имеет значение NULL", и поэтому ваш аргумент не добавляется в исходящий пакет SOAP; что приводит к ошибке отсутствия параметра.

Вы должны расширить этот класс, чтобы удалить проверку. Затем происходит большой снежный ком по цепочке, изменяя SOAPEncoder, чтобы использовать измененный XMLEncoder, а затем изменяя операцию для использования вашего модифицированного SOAPEncoder, а затем moidfying WebService для использования вашего альтернативного класса Operation.

Я потратил несколько часов на это, но мне нужно двигаться дальше. Вероятно, это займет день или два.

Возможно, вы сможете просто исправить строку XMLEncoder и выполнить некоторые исправления для обезьян, чтобы использовать свой собственный класс.

Я также добавлю, что если вы переключитесь на использование RemoteObject/AMF с ColdFusion, нуль передается без проблем.


Обновление за 11/16/2012:

У меня есть еще одно последнее дополнение к моему последнему комментарию о RemoteObject/AMF. Если вы используете CF10; то свойства с нулевым значением для объекта удаляются из объекта на стороне сервера. Таким образом, перед доступом к нему необходимо проверить наличие свойств или получить ошибку времени выполнения. Проверьте следующее:

<cfif (structKeyExists(arguments.myObject,'propertyName')>
 <!--- no property code --->
<cfelse>
 <!--- handle property  normally --->
</cfif>

Это изменение в поведении от CF9; где нулевые свойства превратятся в пустые строки.


Редактировать 12/6/2013

Поскольку возник вопрос о том, как обрабатываются нули, это быстрое примерное приложение, демонстрирующее, как строка "null" будет относиться к зарезервированному слову null.

<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" 
               xmlns:s="library://ns.adobe.com/flex/spark" 
               xmlns:mx="library://ns.adobe.com/flex/mx" minWidth="955" minHeight="600" initialize="application1_initializeHandler(event)">
    <fx:Script>
        <![CDATA[
            import mx.events.FlexEvent;

            protected function application1_initializeHandler(event:FlexEvent):void
            {
                var s :String = "null";
                if(s != null){
                    trace('null string is not equal to null reserved word using the != condition');
                } else {
                    trace('null string is equal to null reserved word using the != condition');
                }

                if(s == null){
                    trace('null string is equal to null reserved word using the == condition');
                } else {
                    trace('null string is not equal to null reserved word using the == condition');
                }

                if(s === null){
                    trace('null string is equal to null reserved word using the === condition');
                } else {
                    trace('null string is not equal to null reserved word using the === condition');
                }

            }

        ]]>
    </fx:Script>
    <fx:Declarations>
        <!-- Place non-visual elements (e.g., services, value objects) here -->
    </fx:Declarations>
</s:Application>

Выход трассировки:

нулевая строка не равна нулевому зарезервированному слову, используя условие: = условие

null string не равно нулевому зарезервированному слову, используя условие ==

null string не равно нулевому зарезервированному слову, используя условие ===

Ответ 5

Переведите все символы в их эквиваленты с шестью сущностями. В этом случае Null будет преобразован в &#4E;&#75;&#6C;&#6C;

Ответ 6

Строка значения null в ActionScript даст строку "NULL". Мое подозрение в том, что кто-то решил, что это хорошая идея, чтобы декодировать строку "NULL" как null, вызывая обрыв, который вы видите здесь, вероятно, потому, что они проходили объекты null и получали строки в в базе данных, когда они этого не хотели (так что обязательно проверяйте эту ошибку).

Ответ 7

В качестве взлома вы можете подумать о специальной обработке на стороне клиента, конвертируя строку "Null" в то, что никогда не произойдет, например, XXNULLXX и преобразование обратно на сервер.

Это не очень, но это может решить проблему для такого граничного случая.

Ответ 8

Ну, я полагаю, что реализация Flex в SOAP Encoder, по-видимому, неправильно упорядочивает нулевые значения. Сериализация их как String Null, похоже, не является хорошим решением. Формально правильная версия, похоже, должна передать пустое значение как:

<childtag2 xsi:nil="true" />

Таким образом, значение "Null" будет не чем иным, как допустимой строкой, что именно то, что вы ищете.

Я предполагаю, что это исправление в Apache Flex не должно быть так сложно сделать. Я бы рекомендовал открыть проблему Jira или связаться с ребятами из списка рассылки apache-flex. Однако это только исправит клиентскую сторону. Я не могу сказать, сможет ли ColdFusion работать с нулевыми значениями, закодированными таким образом.

См. также сообщение в блоге Radu Cotescu Как отправить нулевые значения в soapUI-запросы.

Ответ 9

Это kludge, но при условии, что для SEARCHSTRING минимальная длина, например, 2 символа, substring параметр SEARCHSTRING для второго символа и вместо этого передайте его как два параметра: SEARCHSTRING1 ("Nu") и SEARCHSTRING2 ("ll"). Concatenate их обратно вместе при выполнении запроса в базу данных.