So übergeben Sie "Null" (einen echten Nachnamen!) An einen SOAP-Webdienst in ActionScript 3

4636

Wir haben einen Mitarbeiter, dessen Nachname Null ist. Unsere Mitarbeiter-Suchanwendung wird beendet, wenn dieser Nachname als Suchbegriff verwendet wird (was derzeit häufig vorkommt). Der Fehler (danke Fiddler!) Ist:

<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>

Süß, oder?

Der Parametertyp ist string.

Ich benutze:

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

Beachten Sie, dass der Fehler nicht auftritt, wenn der Webservice als Objekt von einer ColdFusion-Seite aufgerufen wird.

Rechnung
quelle
6
Es mag Ihnen bei dem spezifischen Problem nicht so viel helfen, aber SOAP 1.2 erlaubt nullbare Werte, siehe w3.org/TR/2001/WD-soap12-20010709/#_Toc478383513
JensG
6
Ich habe das Gefühl, es geht um Dave Null.
George Gibson
2
Zumindest geht es nicht um Chuck Norris. Hier ist, warum Sie sich im Code von ihm fernhalten
sollten
42
Hat der Mitarbeiter überlegt, seinen Namen zu ändern?
Tatranskymedved
11
Er sollte wirklich erwägen den Kauf Pointer Hund und ihn Nullpointer rufen.
Antonio Alvarez

Antworten:

1109

Aufspüren

Zuerst dachte ich, dies sei ein Zwangsfehler, zu dem nullman gezwungen wurde "null"und an dem ein Test "null" == nullbestanden wurde. Es ist nicht. Ich war nah dran, aber so sehr, sehr falsch. Das tut mir leid!

Ich habe seitdem viel auf Wonderfl.net herumgespielt und den Code in nachverfolgtmx.rpc.xml.* . In Zeile 1795 von XMLEncoder(in der 3.5-Quelle) in setValueläuft die gesamte XMLEn-Codierung auf

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

Das ist im Wesentlichen das gleiche wie:

currentChild.appendChild("null");

Dieser Code gibt meiner ursprünglichen Geige zufolge ein leeres XML-Element zurück. Aber warum?

Ursache

Laut dem Kommentator Justin Mclean zum Fehlerbericht FLEX-33664 ist das Folgende der Schuldige (siehe die letzten beiden Tests in meiner Geige, die dies bestätigen):

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
}

Wenn currentChild.appendChilddie Zeichenfolge übergeben wird "null", wird sie zuerst in ein XML-Stammelement mit Text konvertiert nullund anschließend mit dem Nullliteral getestet. Dies ist ein schwacher Gleichheitstest. Daher wird entweder das XML mit Null zum Nulltyp oder der Nulltyp zu einem XML-Stammelement mit der Zeichenfolge "Null" gezwungen, und der Test besteht dort, wo er möglicherweise fehlschlagen sollte. Eine Lösung könnte darin bestehen, immer strenge Gleichheitstests zu verwenden, wenn XML (oder irgendetwas anderes) auf "Nullheit" überprüft wird.

Lösung

Die einzige vernünftige Problemumgehung, die ich mir vorstellen kann, ohne diesen Fehler in jeder verdammten Version von ActionScript zu beheben, besteht darin, Felder auf "null" zu testen und sie als CDATA-Werte zu maskieren .

CDATA-Werte sind die am besten geeignete Methode, um einen gesamten Textwert zu mutieren, der sonst zu Codierungs- / Decodierungsproblemen führen würde. Die Hex-Codierung ist beispielsweise für einzelne Zeichen gedacht. CDATA-Werte werden bevorzugt, wenn Sie den gesamten Text eines Elements maskieren. Der Hauptgrund dafür ist, dass die menschliche Lesbarkeit erhalten bleibt.

Ben Burns
quelle
298

Auf der xkcd-Anmerkung finden Sie auf der Bobby Tables-Website gute Ratschläge, um die falsche Interpretation von Benutzerdaten (in diesem Fall die Zeichenfolge "Null") in SQL-Abfragen in verschiedenen Sprachen, einschließlich ColdFusion, zu vermeiden .

Aus der Frage geht nicht hervor, dass dies die Ursache des Problems ist, und angesichts der Lösung, die in einem Kommentar zur ersten Antwort (Einbetten der Parameter in eine Struktur) angegeben ist, scheint es wahrscheinlich, dass es sich um etwas anderes handelte.

Alex Dupuy
quelle
239

Das Problem könnte im SOAP-Encoder von Flex liegen. Versuchen Sie, den SOAP-Encoder in Ihrer Flex-Anwendung zu erweitern, und debuggen Sie das Programm, um zu sehen, wie der Nullwert behandelt wird.

Ich vermute, es wird als NaN (Not a Number) übergeben. Dies wird den SOAP-Nachrichten-Unmarshalling-Prozess irgendwann durcheinander bringen (insbesondere auf dem JBoss 5-Server ...). Ich erinnere mich, dass ich den SOAP-Encoder erweitert und explizit überprüft habe, wie mit NaN umgegangen wird.

uncaught_exceptions
quelle
12
name = "Null" ist natürlich nützlich, und ich sehe nicht, wie es mit NaN zusammenhängen soll.
eckes
129

@ doc_180 hatte das richtige Konzept, außer dass er sich auf Zahlen konzentriert, während das Originalplakat Probleme mit Zeichenfolgen hatte.

Die Lösung besteht darin, die mx.rpc.xml.XMLEncoderDatei zu ändern . Dies ist Zeile 121:

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

(Ich habe mir das Flex 4.5.1 SDK angesehen. Die Zeilennummern können in anderen Versionen abweichen.)

Grundsätzlich schlägt die Validierung fehl, da "Inhalt null" ist und Ihr Argument daher nicht zum ausgehenden SOAP-Paket hinzugefügt wird. Dadurch wird der fehlende Parameterfehler verursacht.

Sie müssen diese Klasse erweitern, um die Validierung zu entfernen. Dann gibt es einen großen Schneeball in der Kette, der SOAPEncoder ändert, um Ihren modifizierten XMLEncoder zu verwenden, und dann Operation ändert, um Ihren modifizierten SOAPEncoder zu verwenden, und dann WebService, um Ihre alternative Operationsklasse zu verwenden.

Ich habe ein paar Stunden damit verbracht, aber ich muss weitermachen. Es wird wahrscheinlich ein oder zwei Tage dauern.

Möglicherweise können Sie einfach die XMLEncoder-Zeile reparieren und Affen-Patches durchführen , um Ihre eigene Klasse zu verwenden.

Ich werde auch hinzufügen, dass, wenn Sie mit ColdFusion auf RemoteObject / AMF umsteigen, die Null ohne Probleme übergeben wird.


16.11.2013 Update :

Ich habe einen weiteren Neuzugang zu meinem letzten Kommentar zu RemoteObject / AMF. Wenn Sie ColdFusion 10 verwenden; Dann werden Eigenschaften mit einem Nullwert für ein Objekt aus dem serverseitigen Objekt entfernt. Sie müssen also vor dem Zugriff prüfen, ob Eigenschaften vorhanden sind, da sonst ein Laufzeitfehler angezeigt wird.

Überprüfen Sie wie folgt:

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

Dies ist eine Verhaltensänderung gegenüber ColdFusion 9. Dabei würden die Null-Eigenschaften zu leeren Zeichenfolgen.


Bearbeiten 06.12.2013

Da es eine Frage zur Behandlung von Nullen gab, finden Sie hier eine kurze Beispielanwendung, um zu demonstrieren, wie sich eine Zeichenfolge "null" auf das reservierte Wort null bezieht.

<?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>

Die Trace-Ausgabe lautet:

null string ist nicht gleich null reserviertem Wort unter Verwendung der Bedingung! =

null string ist nicht gleich null reserviertem Wort unter Verwendung der == Bedingung

null string ist nicht gleich null reserviertem Wort unter Verwendung der Bedingung ===

JeffryHouser
quelle
8
@ Reboog711 Der Nachname des Mitarbeiters ist buchstäblich die Zeichenfolge "Null" wie in "Mein Name ist Pat Null". Ihre Antwort gibt den Nachnamen des Mitarbeiters nicht weiter. Ihre Antwort verbirgt nur die Tatsache, dass "Null" durch die von Ben Burns beschriebene appendChild () -Methode unangemessen in das Sprachkonzept von null gezwungen wird. Das Ergebnis ist immer noch ein Versagen des Systems, mit Herrn oder Frau Null umzugehen.
Maxx Daymon
2
@ MaxxDaymon Ich denke, Sie verstehen falsch, was meine Antwort tatsächlich ist. Es bietet keine Lösung; sondern eine Erklärung, warum das Problem auftritt; und zitiert relevanten Code aus dem Flex Framework. Meine neuere Bearbeitung ist möglicherweise verlegt. da es einen alternativen Ansatz diskutiert und nicht direkt mit der ursprünglichen Frage zusammenhängt.
JeffryHouser
1
Sie sind auf dem richtigen Weg, aber an diesem Punkt im Code contentbefindet sich die Zeichenfolge "null", und "null" == null gibt false zurück, sodass sich der Test wie beabsichtigt verhält. Stattdessen glaube ich, dass das Problem darin besteht, wie XML.appendChild mit einem Zeichenfolgenargument umgeht und wie ein XML-Stammelement, das nur die Zeichenfolge "null" enthält, zu einem Literal gezwungen werden kann null.
Ben Burns
@ Reboog711 Schau dir meine Geige an. "null"! = null` Rückgabe trueist hier gewünschtes Verhalten. Wenn das Gegenteil passieren würde, würde dies die Zeichenfolge "null" aus dem Codierungsprozess verwerfen, was tatsächlich die Ursache des Problems wäre. Da dieser Test jedoch erfolgreich ist, läuft der Encoder weiter, bis XML.appendChild ihn aufgrund eines Zwangsfehlers verwirft.
Ben Burns
4
Keine Sorge. Wenn Sie das eigentliche Problem sehen möchten, fügen Sie var xml:XML = <root>null</root>; var s:String = (xml == null) ? "wtf? xml coerced to null?!!" : "xml not coerced to null."; trace(s);es Ihrem Codebeispiel hinzu.
Ben Burns
65

Übersetzen Sie alle Zeichen in ihre Hex-Entitätsäquivalente. In diesem Fall Nullwürde in konvertiert&#4E;&#75;&#6C;&#6C;

Google
quelle
41
Bitte tu das nicht. CDATA wurde für den Fall erstellt, dass Sie einen ganzen Textblock maskieren müssen.
Ben Burns
4
Ich könnte mich irren, aber ich denke nicht, dass Downvoting, nur weil es nicht Ihre Lösung war, so funktioniert. Sie müssen auch berücksichtigen, dass das Problem eine heuristische Lösung erfordert, da es keinen offensichtlichen Weg gibt, wie die Vielzahl der veröffentlichten Lösungen zeigt. Wenn ich bedenke, dass ich CF nicht kenne, würde ein Decoder nicht einfach den inneren Text von <message> <! [CDATA [NULL]> </ message> mit dem inneren Text von <message> NULL </ gleichsetzen. Nachricht>? Wenn ja, ist CDATA dann überhaupt eine Lösung?
Google
7
Ich habe abgelehnt, weil dies ein Anti-Muster ist. Der Fehler in diesem Fall liegt nicht in CF, sondern in ActionScript. Sie sprechen jedoch einen guten Punkt an. Ich werde meiner Geige einen Test für die CDATA-Codierung hinzufügen.
Ben Burns
51

Wenn Sie einen nullWert in ActionScript kennzeichnen , erhalten Sie die Zeichenfolge "NULL". Mein Verdacht ist, dass jemand entschieden hat, dass es daher eine gute Idee ist, die Zeichenfolge "NULL"als zu dekodieren null, was den hier angezeigten Bruch verursacht - wahrscheinlich, weil er nullObjekte übergeben und Zeichenfolgen in die Datenbank aufgenommen hat, als er dies nicht wollte das (also stellen Sie sicher, dass Sie auch nach solchen Fehlern suchen).

Andrew Aylett
quelle
Ja, hier gibt es eine Reihe von Möglichkeiten, für deren Eingrenzung mehr Debugging erforderlich ist. 1) Ist die hier verwendete WSDL aussagekräftig genug, um zwischen "NULL" als Zeichenfolgenwert und einem tatsächlichen Nullwert (oder ausgelassenen Wert) zu unterscheiden? 2) Wenn ja, codiert der Client den Nachnamen korrekt (als Zeichenfolge und nicht als Nullliteral). 3) Wenn ja, interpretiert der Dienst "NULL" ordnungsgemäß als Zeichenfolge oder erzwingt er einen Nullwert?
Pimlottc
39

Als Hack könnten Sie eine spezielle Behandlung auf der Clientseite in Betracht ziehen, indem Sie die Nullzeichenfolge in etwas konvertieren, das niemals auftreten wird, z. B. XXNULLXX, und die Konvertierung wieder auf dem Server durchführen.

Es ist nicht schön, aber es kann das Problem für einen solchen Grenzfall lösen.

Kennzeichen
quelle
32
XXNULLXX könnte auch ein Name sein. Du weißt es nicht. Vielleicht haben Menschen in Indonesien keinen Nachnamen und verwenden bei Bedarf eine Variante von XXX als Nachnamen.
gb.
3
Gleiches Konzept, aber aktualisieren Sie alle Namen in der Datenbank und das Vorwort dann mit einem Zeichen (1Null, 1Smith). Entfernen Sie dieses Zeichen im Client. Natürlich könnte dies eine Milbenarbeit sein als die Lösung von Reboog.
Bobpaul
14
@ BenBurns Ja, aber was ist, wenn ich mein Kind benennen möchte &#78;&#117;&#108;&#108;?
Sirenen
@ Sirens Das ist nicht das Problem. Wenn mein Name "<& quot;>" ist, dann erwarte ich, dass er ordnungsgemäß als "& lt; & amp;" & gt; "maskiert wird, was selbstverständlich ist. Das eigentliche Problem besteht darin, dass sich eine Anwendung so verhält, als würde sie eine schwarze Liste für Namen verwenden.
Herr Lister
30

Nun, ich denke, dass die Flex-Implementierung des SOAP-Encoders Nullwerte falsch zu serialisieren scheint. Die Serialisierung als String Null scheint keine gute Lösung zu sein. Die formal korrekte Version scheint darin zu bestehen, einen Nullwert zu übergeben als:

<childtag2 xsi:nil="true" />

Der Wert von "Null" wäre also nichts anderes als eine gültige Zeichenfolge, genau das, wonach Sie suchen.

Ich denke, dass es nicht so schwer sein sollte, dies in Apache Flex zu beheben. Ich würde empfehlen, ein Jira-Problem zu eröffnen oder sich an die Leute der Apache-Flex-Mailingliste zu wenden. Dies würde jedoch nur die Client-Seite reparieren. Ich kann nicht sagen, ob ColdFusion mit auf diese Weise codierten Nullwerten arbeiten kann.

Siehe auch Radu Cotescus Blog-Beitrag So senden Sie Nullwerte in soapUI-Anfragen .

Christofer Dutz
quelle
6
Es gibt hier gute Informationen, daher werde ich nicht abstimmen, aber ich dachte, es ist einen Kommentar wert. Standardmäßig codiert XMLEncoder.as einen wahren nullWert ordnungsgemäß, indem xsi:nil="true"das Element festgelegt wird. Das Problem scheint tatsächlich darin zu liegen, wie der ActionScript- XMLTyp selbst (nicht der Encoder) mit der Zeichenfolge umgeht "null".
Ben Burns
22

Es ist ein Kludge, aber vorausgesetzt, es gibt eine Mindestlänge SEARCHSTRINGfür beispielsweise 2 Zeichen, substringden SEARCHSTRINGParameter am zweiten Zeichen, und übergeben Sie ihn stattdessen als zwei Parameter: SEARCHSTRING1 ("Nu")und SEARCHSTRING2 ("ll"). Concatenatesie wieder zusammen, wenn Sie die Abfrage an die Datenbank ausführen.

SPitBalls.com
quelle
32
CDATA wurde der XML-Spezifikation hinzugefügt, um diese Art von Kludges zu vermeiden.
Ben Burns
8
Es ist nicht erforderlich, "Null" mit CDATA zu umgehen, es gibt kein Null-Schlüsselwort in XML.
eckes
6
Stimmen Sie mit @eckes überein. Ich verstehe nicht, warum von CDATA die ganze Rede ist. CDATA ist nur nützlich, um Zeichen zu maskieren, die in XML eine besondere Bedeutung haben. Keine von: n,, uhat leine spezielle Semantik in XML. "NULL" und "<! [CDATA [NULL]]>" sind identisch mit einem XML-Parser.
Jason Karns
9
@jasonkarns - Ich stimme zu 100% zu, dass der String / Text-Knoten nichts Besonderes sein sollteNULL , sondern pedantisch sein sollte <blah>null</blah>und <blah><![CDATA[null]]>nicht mit einem XML-Parser identisch ist. Sie sollten die gleichen Ergebnisse liefern, jedoch ist der logische Ablauf für ihre Behandlung unterschiedlich. Diesen Effekt nutzen wir als Problemumgehung für den Fehler in der Flex-XML-Implementierung. Ich befürworte dies gegenüber anderen Ansätzen, da es die Lesbarkeit des Textes bewahrt und keine Nebenwirkungen für andere Parser hat.
Ben Burns