Як передати "Null" (справжнє прізвище!) Веб-сервісу SOAP в ActionScript 3


4635

У нас є співробітник, прізвище якого 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
Принаймні, це не стосується Чака Норріса. Ось чому триматися подалі від нього в коді: codequeeze.com/…
SDsolar

42
Чи думав працівник змінити своє ім’я?
Tatranskymedved

11
Він дійсно повинен розглянути можливість придбання собаки вказівника і назвати його NullPointer.
Антоніо Альварес

Відповіді:


1108

Відстежуючи це

Спочатку я подумав, що це помилка примусу, до якої 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, примусовий до нульового типу, або нульовий тип примусовий до кореневого елемента 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.


12
name = "Null" - це, звичайно, корисно, і я не бачу, як це має бути пов'язано з NaN.
eckes

129

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

Рішення - змінити mx.rpc.xml.XMLEncoderфайл. Це рядок 121:

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

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

В основному, перевірка не вдається, оскільки "вміст є нульовим", і тому ваш аргумент не додається до вихідного пакету SOAP; таким чином викликаючи помилку відсутнього параметра.

Ви повинні розширити цей клас, щоб видалити перевірку. Потім з'являється велика снігова куля в ланцюзі, модифікуючи SOAPEncoder для використання вашої модифікованої XMLEncoder, а потім модифікуючи Операцію для використання зміненого SOAPEncoder, а потім мобілізуючи WebService для використання альтернативного класу операцій.

Я витратив на це кілька годин, але мені потрібно рухатись далі. Можливо, це займе день чи два.

Можливо, ви зможете просто виправити лінію 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.

<?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 не дорівнює нулю зарезервованого слова, використовуючи умову! =

рядок null не дорівнює нульовому зарезервованому слову, використовуючи умову ==

рядок null не дорівнює нульовому зарезервованому слову, використовуючи умову ===


8
@ Reboog711 Прізвище працівника - це буквально рядок "Null", як у "My name is Pat Null". Ваша відповідь не відповідає прізвищу працівника. Ви відповідаєте, просто приховує той факт, що "Null" неналежним чином примусово застосовується до мовної концепції null методом appendChild (), як описав Бен Бернс. Результатом все ж є невдача системи впоратися з паном чи пані Нулл.
Maxx Daymon

2
@MaxxDaymon Я думаю, ви неправильно пояснюєте, що насправді моя відповідь. Він не пропонує рішення; скоріше пояснення, чому виникає проблема; і цитує відповідний код із Flex Framework. Моя остання редакція, можливо, замінена; оскільки він обговорює альтернативний підхід і не пов'язаний безпосередньо з початковим питанням.
JeffryHouser

1
Ви начебто на правильному шляху, але в цей момент у коді contentє рядок "null", і "null" == null повертає помилку, так що тест веде себе за призначенням. Натомість я вважаю, що проблема полягає в поєднанні того, як 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;


41
Будь ласка, не робіть цього. CDATA створений для використання у випадках, коли вам потрібно вийти з цілого блоку тексту.
Бен Бернс

4
Я можу помилятися, але я не думаю, що це спричиняє лише тому, що це було не ваше рішення, як це має працювати. Крім того, ви повинні мати на увазі, що проблема вимагає евристичного вирішення, оскільки не існує одного очевидного способу, як це видно з різноманітності розміщених рішень. Нарешті, маючи на увазі, що я не знаю CF, чи не було б декодер просто прирівняти внутрішній текст <message><!ptedCDATA evidenceNULLSensecharge> </message> до внутрішнього тексту <message> NULL </ повідомлення>? Якщо так, то чи справді CDATA взагалі є рішенням?
doogle

7
Я відмовився, тому що це анти-модель. Помилка в цьому випадку не в CF, це в ActionScript. Однак ви все-таки піднімаєте хорошу точку. Я додам тест до моєї загадки щодо кодування CDATA.
Бен Бернс

51

Послідовне nullзначення в ActionScript дасть рядок"NULL" . Я підозрюю, що хтось вирішив, що це, отже, гарна ідея розшифрувати рядок "NULL"як null, викликаючи поломку, яку ви бачите тут - ймовірно, тому, що вони проходили в nullоб'єктах і отримували рядки в базі даних, коли вони не хотіли це (тому обов'язково перевірте, чи немає і помилок).


Так, тут є ряд можливостей, для яких знадобиться більше налагодження для звуження. 1) Чи використовується тут WSDL досить виразним, щоб розрізняти "NULL" як значення рядка та фактичне нулеве (або пропущене) значення? 2) Якщо так, чи правильно кодує клієнт прізвище (як рядок, а не нульовий буквальний) 3) Якщо так, то чи правильно служба трактує "NULL" як рядок чи примушує її до нульового значення?
pimlottc

39

Як хак, ви можете розглянути можливість спеціальної обробки на стороні клієнта, перетворення рядка "Null" в те, що ніколи не відбудеться, наприклад, XXNULLXX і перетворення назад на сервер.

Це не дуже, але це може вирішити питання для такої граничної справи.


32
XXNULLXX теж може бути ім'ям. Ви не знаєте. Можливо, люди в Індонезії не мають прізвища та використовують варіант XXX в якості свого прізвища, коли потрібно.
гб.

3
Те саме поняття, але оновіть усі імена в базі даних та передмові, а потім деяким символом (1Null, 1Smith). Скиньте цього персонажа у клієнта. Звичайно, це може бути кліща робота, ніж рішення Reboog.
bobpaul

14
@BenBurns Так, але що робити, якщо я хочу назвати свою дитину &#78;&#117;&#108;&#108;?
Сирени

@Sirens Це не проблема. Якщо мене звуть "<">, я очікую, що це буде належним чином вимкнено як "& quot; & gt;", що само собою зрозуміло. Справжня проблема полягає в тому, що програма поводиться так, ніби вона використовує чорний список для імен.
Містер Лістер

30

Добре, я думаю, що Flex 'реалізація кодера SOAP, здається, неправильно серіалізує нульові значення. Серіалізація їх як String Null не здається вдалим рішенням. Формально правильна версія, здається, повинна передавати нульове значення як:

<childtag2 xsi:nil="true" />

Таким чином, значення "Null" було б не що інше, як дійсна рядок, саме те, що ви шукаєте.

Думаю, виправити це в Apache Flex не повинно так складно. Я рекомендую відкрити випуск Jira або зв’язатися з хлопцями з розсилки апаш-флексу. Однак це лише виправить сторону клієнта. Я не можу сказати, чи зможе ColdFusion працювати з нульовими значеннями, закодованими таким чином.

Дивіться також допис у блозі Раду Котеску Як надсилати нульові значення у запитах soapUI .


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

22

Це ляп, але за умови , що є мінімальна довжина SEARCHSTRING, наприклад , 2 символу, параметр з другим символом і передати його в якості двох параметрів , замість цього: і їх разом при виконанні запиту до бази даних.substringSEARCHSTRINGSEARCHSTRING1 ("Nu")SEARCHSTRING2 ("ll"). Concatenate


32
CDATA було додано до специфікації XML, щоб уникнути подібних помилок.
Бен Бернс

8
Не потрібно уникати "Null" за допомогою CDATA, у XML немає такого ключового слова, як null.
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. Вони повинні давати однакові результати, однак логічний потік для роботи з ними різний. Саме цей ефект ми використовуємо як вирішення помилки в реалізації XML-реалізації. Я виступаю за це над іншими підходами, оскільки він зберігає читабельність тексту і не має побічних ефектів для інших парсерів.
Бен Бернс
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.