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

У нас есть сотрудник с нулевой фамилией. Наше приложение поиска сотрудников прекращается, когда эта фамилия используется в качестве поискового запроса (что сейчас случается довольно часто). Полученная ошибка (спасибо 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.


person bill    schedule 16.12.2010    source источник
comment
Это может не очень помочь вам с конкретной проблемой, но SOAP 1.2 допускает значения, допускающие значение NULL, см. w3.org/TR/2001/WD-soap12-20010709 / # _ Toc478383513   -  person JensG    schedule 08.04.2014
comment
У меня такое чувство, что это касается Дэйва Налла.   -  person    schedule 01.08.2016
comment
По крайней мере, это не касается Чака Норриса. Вот почему нужно держаться от него подальше в коде: codequeeze .com /   -  person SDsolar    schedule 03.06.2017
comment
Задумывался ли сотрудник о смене имени?   -  person Tatranskymedved    schedule 30.06.2017
comment
Ссылка на BBC: bbc.com/future/ история /   -  person biziclop    schedule 29.12.2017
comment
Ему действительно стоит подумать о покупке собаки Pointer и назвать ее NullPointer.   -  person Antonio Alvarez    schedule 22.11.2018
comment
Этот сотрудник должен быть дальним родственником Little Bobby Tables.   -  person Lynn Crumbling    schedule 17.02.2020


Ответы (9)


Отслеживая это

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

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

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

что по сути то же самое, что:

currentChild.appendChild("null");

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

Причина

По словам комментатора Джастина Маклина в отчете об ошибке 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, содержащий null, приводится к нулевому типу, либо нулевой тип приводится к корневому элементу xml, содержащему строку «null», и тест проходит там, где он, возможно, должен завершиться ошибкой. Одно из исправлений - всегда использовать строгое равенство. тесты при проверке XML (или чего-то еще) на «пустоту».

Решение

The only reasonable workaround I can think of, short of fixing this bug in every damn version of ActionScript, is to test fields for "null" and escape them as CDATA values.

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

person Ben Burns    schedule 01.08.2013

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

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

person Alex Dupuy    schedule 27.04.2012

Проблема могла быть в кодировщике SOAP Flex. Попробуйте расширить кодировщик SOAP в своем приложении Flex и отладьте программу, чтобы увидеть, как обрабатывается нулевое значение.

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

person uncaught_exceptions    schedule 16.01.2011
comment
name = Null, конечно, полезен, и я не понимаю, как это должно быть связано с NaN. - person eckes; 16.11.2013

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

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

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

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

Обычно проверка не выполняется, потому что «содержимое равно нулю» и, следовательно, ваш аргумент не добавляется к исходящему пакету SOAP; что вызывает ошибку отсутствующего параметра.

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

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

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

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


Обновление от 16.11.2013:

У меня есть еще одно недавнее добавление к моему последнему комментарию о RemoteObject / AMF. Если вы используете ColdFusion 10; затем свойства с нулевым значением объекта удаляются из объекта на стороне сервера. Итак, вы должны проверить наличие свойств, прежде чем обращаться к ним, иначе вы получите ошибку времени выполнения.

Проверить вот так:

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

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


Изменить 12/6/2013

Поскольку возник вопрос о том, как обрабатываются значения NULL, вот краткий пример приложения, демонстрирующий, как строка «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>

Результат трассировки:

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

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

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

person JeffryHouser    schedule 03.05.2012
comment
@ Reboog711 Фамилия сотрудника буквально представляет собой строку Null, например, меня зовут Pat Null. В вашем ответе не передается фамилия сотрудника. Ваш ответ просто скрывает тот факт, что Null ненадлежащим образом принудительно вводится в языковую концепцию null с помощью метода appendChild (), как описано Беном Бернсом. В результате система по-прежнему не может справиться с мистером или мисс Нулл. - person Maxx Daymon; 22.11.2013
comment
@MaxxDaymon Я думаю, вы неправильно истолковываете мой ответ. Это не предлагает решения; а скорее объяснение того, почему возникает проблема; и цитирует соответствующий код из Flex Framework. Мое последнее изменение, возможно, неуместно; поскольку в нем обсуждается альтернативный подход и не имеет прямого отношения к исходному вопросу. - person JeffryHouser; 22.11.2013
comment
Вы вроде как на правильном пути, но в этот момент в коде content находится строка "null", а null == null возвращает false, так что тест ведет себя так, как задумано. Вместо этого я считаю, что проблема заключается в сочетании того, как XML.appendChild обрабатывает строковый аргумент, и того, как корневой XML-элемент, содержащий только строку null, может быть преобразован в литерал null. - person Ben Burns; 06.12.2013
comment
@ Reboog711 Взгляни на мою скрипку. null! = null` здесь желаемое поведение, возвращающее true. Если бы произошло обратное, это привело бы к исключению строки null из процесса кодирования, что на самом деле было бы причиной проблемы. Однако, поскольку этот тест завершается успешно, кодировщик продолжает работать, пока XML.appendChild не отбросит его из-за ошибки принуждения. - person Ben Burns; 06.12.2013
comment
@BenBurns Забудьте мои предыдущие комментарии, которые я только что удалил. Ты прав. Прошло некоторое время с тех пор, как я собрал образец, чтобы попытаться помочь диагностировать это, и я отчетливо помню, как прошел через эту явную строку кода и получил результаты, которые я задокументировал в ответе. Что касается того, почему это так; Мне сейчас неясно. Я оставил свой образец кода, демонстрирующий, как нулевая строка сравнивается с нулевым зарезервированным словом, что в точности соответствует тому, что вы сказали. - person JeffryHouser; 06.12.2013
comment
Не стоит беспокоиться. Если вы хотите увидеть реальную проблему, добавьте var xml:XML = <root>null</root>; var s:String = (xml == null) ? "wtf? xml coerced to null?!!" : "xml not coerced to null."; trace(s); в образец кода. - person Ben Burns; 06.12.2013

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

person doogle    schedule 30.04.2012
comment
Пожалуйста, не делай этого. CDATA был создан для использования в тех случаях, когда вам нужно экранировать весь блок текста. - person Ben Burns; 06.12.2013
comment
Я могу ошибаться, но я не думаю, что голосование "против" только потому, что это не было вашим решением, - это то, как оно должно работать. Также вы должны иметь в виду, что проблема требует эвристического решения, поскольку не существует одного очевидного способа, о чем свидетельствует разнообразие опубликованных решений. Наконец, имея в виду, что я не знаю CF, не мог бы декодер просто приравнять внутренний текст ‹message› ‹! [CDATA [NULL]]› ‹/message› к внутреннему тексту ‹message› NULL ‹/ сообщение>? Если да, то действительно ли CDATA - это вообще решение? - person doogle; 06.12.2013
comment
Я проголосовал против, потому что это антипаттерн. Ошибка в этом случае не в CF, а в ActionScript. Однако, тем не менее, вы поднимаете хороший вопрос. Я добавлю к своей скрипке тест для кодирования CDATA. - person Ben Burns; 19.12.2013

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

person Andrew Aylett    schedule 28.04.2012
comment
Да, здесь есть ряд возможностей, которые потребуют дополнительной отладки, чтобы сузить круг вопросов. 1) Используется ли здесь WSDL достаточно выразительно, чтобы различать NULL как строковое значение и фактическое нулевое (или пропущенное) значение? 2) Если да, правильно ли клиент кодирует фамилию (как строку, а не как нулевой литерал) 3) Если да, правильно ли служба интерпретирует NULL как строку или приводит ее к нулевому значению? - person pimlottc; 18.11.2013

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

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

person Mark    schedule 28.04.2012
comment
XXNULLXX тоже может быть именем. Вы не знаете. Возможно, люди в Индонезии не имеют фамилии и при необходимости используют в качестве фамилии вариант XXX. - person gb.; 02.08.2013
comment
Та же концепция, но обновите все имена в базе данных и введите какой-нибудь символ (1Null, 1Smith). Уберите этого персонажа в клиенте. Конечно, это может быть более мелкая работа, чем решение Reboog. - person bobpaul; 16.11.2013
comment
@BenBurns Да, но что, если я хочу назвать своего ребенка &#78;&#117;&#108;&#108;? - person Allison; 12.05.2015
comment
@Sirens Проблема не в этом. Если меня зовут ‹›, я ожидаю, что оно будет правильно экранировано как quot;, что само собой разумеется. Настоящая проблема заключается в том, что приложение ведет себя так, как если бы оно использовало черный список для имен. - person Mr Lister; 17.04.2017

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

<childtag2 xsi:nil="true" />

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

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

См. Также сообщение в блоге Раду Котеску Как отправлять нулевые значения в запросах soapUI.

person Christofer Dutz    schedule 17.07.2013
comment
Здесь есть хорошая информация, поэтому я не буду отрицать, но я подумал, что стоит прокомментировать. По умолчанию XMLEncoder.as фактически правильно кодирует истинное значение null, устанавливая xsi:nil="true" в элементе. На самом деле проблема заключается в том, как сам тип ActionScript XML (а не кодировщик) обрабатывает строку "null". - person Ben Burns; 02.08.2013

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

person SPitBalls.com    schedule 28.04.2012
comment
CDATA был добавлен в спецификацию XML, чтобы избежать подобных проблем. - person Ben Burns; 02.08.2013
comment
Нет необходимости экранировать Null с помощью CDATA, в XML нет такого понятия, как ключевое слово null. - person eckes; 18.04.2015
comment
Согласен с @eckes. Я не понимаю, почему все говорят о CDATA. CDATA используется только для экранирования символов, имеющих особое значение в XML. ни один из: n, u, l не имеет специальной семантики в XML. NULL и ‹! [CDATA [NULL]]› идентичны синтаксическому анализатору XML. - person jasonkarns; 18.04.2015
comment
@jasonkarns - Я на 100% согласен с тем, что не должно быть ничего особенного в строковом / текстовом узле NULL, но, чтобы быть педантичным, <blah>null</blah> и <blah><![CDATA[null]]> не одно и то же для синтаксического анализатора XML. Они должны давать одинаковые результаты, однако логическая схема их обработки отличается. Именно этот эффект мы используем как обходной путь к ошибке в реализации гибкого XML. Я рекомендую этот подход по сравнению с другими подходами, поскольку он сохраняет читабельность текста и не имеет побочных эффектов для других синтаксических анализаторов. - person Ben Burns; 08.09.2015