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

4636

У нас есть сотрудник с фамилией 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.

счет
источник
6
Это может вам не сильно помочь с конкретной проблемой, но SOAP 1.2 допускает значения, которые можно обнулять
JensG
6
У меня есть ощущение, что это касается Дейва Налла.
Джордж Гибсон
2
По крайней мере, это не касается Чака Норриса. Вот почему , чтобы держаться подальше от него в коде: codesqueeze.com/...
SDsolar
42
Рассматривал ли сотрудник сменить имя?
Tatranskymedved
11
Он действительно должен подумать о покупке собаки Pointer и называть его NullPointer.
Антонио Альварес

Ответы:

1109

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

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

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

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 (или чего-то еще) на «нулевое значение».

Решение

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

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

Бен Бернс
источник
298

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

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

Алекс Дюпуй
источник
239

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

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

uncaught_exceptions
источник
12
name = "Null", конечно, полезно, и я не понимаю, как это должно быть связано с NaN.
eckes
129

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

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

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

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

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

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

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

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

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


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

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

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

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

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


Изменить 6/12/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>

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

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

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

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

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

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

Doogle
источник
41
Пожалуйста, не делай этого. CDATA была создана для использования в тех случаях, когда вам нужно экранировать целый блок текста.
Бен Бернс
4
Я могу ошибаться, но я не думаю, что отказывать в голосовании просто потому, что это не ваше решение, как это должно работать. Также вы должны иметь в виду, что проблема требует эвристического решения, так как не существует одного очевидного пути, о чем свидетельствует разнообразие опубликованных решений. Наконец, имея в виду, что я не знаю CF, не будет ли декодер просто приравнять внутренний текст <message> <! [CDATA [NULL]]> </ message> к внутреннему тексту <message> NULL </ сообщение>? Если так, то действительно ли CDATA является решением вообще?
Google
7
Я понизил голос, потому что это анти-шаблон. Ошибка в этом случае не в CF, а в ActionScript. Тем не менее, вы поднимаете хороший вопрос, тем не менее. Я добавлю тест на мою скрипку для кодирования CDATA.
Бен Бернс
51

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

Эндрю Айлетт
источник
Да, здесь есть ряд возможностей, которые потребуют больше отладки для сужения. 1) Является ли WSDL, используемый здесь, достаточно выразительным, чтобы различать «NULL» как строковое значение и фактическое нулевое (или пропущенное) значение? 2) Если это так, правильно ли клиент кодирует фамилию (в виде строки, а не литерала NULL)? 3) Если да, то правильно ли служба интерпретирует «NULL» как строку, или приводит его к нулевому значению?
pimlottc
39

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

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

отметка
источник
32
XXNULLXX тоже может быть именем. Вы не знаете Возможно, люди в Индонезии не имеют фамилии и при необходимости используют вариант XXX в качестве своей фамилии.
Гб.
3
Та же концепция, но обновите все имена в базе данных, а затем введите предисловие с помощью некоторого символа (1Null, 1Smith). Уберите этого персонажа из клиента. Конечно, это может быть бесполезной работой, чем решение Ребуга.
Бобпол
14
@BenBurns Да, но что если я захочу назвать своего ребенка &#78;&#117;&#108;&#108;?
Сирены
@ Сирены Это не проблема. Если меня зовут "<">, тогда я ожидаю, что он будет правильно экранирован как "& lt; & amp; quot;", что само собой разумеется. Настоящая проблема заключается в том, что приложение ведет себя так, как будто оно использует черный список для имен.
Мистер Листер
30

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

<childtag2 xsi:nil="true" />

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

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

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

Кристофер Дутц
источник
6
Здесь есть хорошая информация, поэтому я не буду понижать голос, но я подумал, что это стоит комментариев. По умолчанию XMLEncoder.as на самом деле nullправильно кодирует истинное значение, устанавливая xsi:nil="true"элемент. Проблема на самом деле заключается в том, как сам XMLтип ActionScript (а не кодировщик) обрабатывает строку "null".
Бен Бернс
22

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

SPitBalls.com
источник
32
CDATA был добавлен в спецификацию XML, чтобы избежать этих типов ошибок.
Бен Бернс
8
С CDATA не нужно экранировать «Ноль», в XML нет такого понятия, как ключевое слово «ноль».
eckes
6
Согласитесь с @eckes. Я не понимаю, почему все эти разговоры о CDATA. CDATA полезен только для экранирования символов, которые имеют особое значение в XML. ни один из: n, u, lне имеют специальной семантики в XML. «NULL» и «<! [CDATA [NULL]]>» идентичны анализатору XML.
jasonkarns
9
@jasonkarns - я согласен на 100%, что в строковом / текстовом узле не должно быть ничего особенного NULL, кроме педантичности, <blah>null</blah>а <blah><![CDATA[null]]>не парсера XML. Они должны давать одинаковые результаты, однако логический поток для их обработки отличается. Именно этот эффект мы используем в качестве обходного пути к ошибке в реализации flex XML. Я защищаю это по сравнению с другими подходами, так как это сохраняет читабельность текста и не имеет побочных эффектов для других анализаторов.
Бен Бернс