Comment passer «Null» (un vrai nom de famille!) À un service Web SOAP dans ActionScript 3


4636

Nous avons un employé dont le nom de famille est Null. Notre application de recherche d'employés est supprimée lorsque ce nom de famille est utilisé comme terme de recherche (ce qui est assez fréquent maintenant). L'erreur reçue (merci Fiddler!) Est:

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

Mignon, hein?

Le type de paramètre est string.

J'utilise:

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

Notez que l'erreur ne se produit pas lors de l'appel du webservice en tant qu'objet à partir d'une page ColdFusion.


6
Cela peut ne pas vous aider beaucoup avec le problème spécifique, mais SOAP 1.2 permet des valeurs nullables
JensG

6
J'ai le sentiment que cela implique Dave Null.
George Gibson

2
Au moins, cela n'implique pas Chuck Norris. Voici pourquoi rester loin de lui dans le code: codesqueeze.com/…
SDsolar

42
L'employé a-t-il envisagé de changer son nom?
Tatranskymedved

11
Il devrait vraiment envisager d'acheter un chien Pointer et de l'appeler NullPointer.
Antonio Alvarez

Réponses:


1109

Le retrouver

Au début, je pensais que c'était un bug de coercition dans lequel on nullétait contraint "null"et un test de "null" == nullréussite. Ce n'est pas. J'étais proche, mais tellement, très mal. Désolé pour ça!

J'ai depuis fait beaucoup de tripotage sur wonderfl.net et de traçage à travers le code dans mx.rpc.xml.*. À la ligne 1795 de XMLEncoder(dans la source 3.5), dans setValue, tous les XMLEncoding se résument à

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

qui est essentiellement le même que:

currentChild.appendChild("null");

Ce code, selon mon violon d'origine, renvoie un élément XML vide. Mais pourquoi?

Cause

Selon le commentateur Justin Mclean sur le rapport de bug FLEX-33664 , le coupable est le suivant (voir les deux derniers tests dans mon violon qui le vérifient):

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
}

Lorsque currentChild.appendChildla chaîne est passée "null", elle la convertit d'abord en un élément XML racine avec du texte null, puis teste cet élément par rapport au littéral nul. Il s'agit d'un test d'égalité faible, donc soit le XML contenant null est contraint au type null, soit le type null est contraint à un élément racine xml contenant la chaîne "null", et le test réussit là où il devrait sans doute échouer. Un correctif pourrait être de toujours utiliser des tests d' égalité stricts lors de la vérification de la nullité de XML (ou n'importe quoi, vraiment).

Solution

La seule solution raisonnable à laquelle je peux penser, à moins de corriger ce bogue dans chaque fichue version d'ActionScript, est de tester les champs pour "null" et de les échapper en tant que valeurs CDATA .

Les valeurs CDATA sont le moyen le plus approprié de muter une valeur de texte entière qui, autrement, provoquerait des problèmes d'encodage / décodage. Le codage hexadécimal, par exemple, est destiné à des caractères individuels. Les valeurs CDATA sont préférées lorsque vous échappez au texte entier d'un élément. La principale raison en est qu'il maintient la lisibilité humaine.


298

Sur la note xkcd , le site Web de Bobby Tables a de bons conseils pour éviter l'interprétation incorrecte des données utilisateur (dans ce cas, la chaîne "Null") dans les requêtes SQL dans diverses langues, y compris ColdFusion .

Il ne ressort pas clairement de la question que c'est la source du problème, et compte tenu de la solution notée dans un commentaire à la première réponse (intégration des paramètres dans une structure), il semble probable qu'il s'agissait d'autre chose.


239

Le problème pourrait être dans l'encodeur SOAP de Flex. Essayez d'étendre l'encodeur SOAP dans votre application Flex et déboguez le programme pour voir comment la valeur nulle est gérée.

Je suppose que c'est passé comme NaN (pas un nombre). Cela gâchera le processus de démasquage des messages SOAP à un moment donné (notamment sur le serveur JBoss 5 ...). Je me souviens avoir étendu l'encodeur SOAP et effectué une vérification explicite sur la façon dont NaN est géré.


12
name = "Null" est bien sûr utile, et je ne vois pas comment cela devrait être lié à NaN.
vérifie

129

@ doc_180 avait le bon concept, sauf qu'il se concentre sur les nombres, alors que l'affiche originale avait des problèmes avec les chaînes.

La solution est de changer le mx.rpc.xml.XMLEncoderfichier. Il s'agit de la ligne 121:

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

(J'ai regardé Flex 4.5.1 SDK; les numéros de ligne peuvent différer dans d'autres versions.)

Fondamentalement, la validation échoue car «le contenu est nul» et votre argument n'est donc pas ajouté au paquet SOAP sortant; provoquant ainsi l'erreur de paramètre manquante.

Vous devez étendre cette classe pour supprimer la validation. Ensuite, il y a une grosse boule de neige dans la chaîne, modifiant SOAPEncoder pour utiliser votre XMLEncoder modifié, puis modifiant Operation pour utiliser votre SOAPEncoder modifié, puis moidfying WebService pour utiliser votre autre classe Operation.

J'y ai passé quelques heures, mais je dois continuer. Cela prendra probablement un jour ou deux.

Vous pourrez peut-être simplement corriger la ligne XMLEncoder et faire quelques patches de singe pour utiliser votre propre classe.

J'ajouterai également que si vous passez à l'utilisation de RemoteObject / AMF avec ColdFusion, la valeur null est transmise sans problème.


Mise à jour du 16/11/2013 :

J'ai un ajout récent à mon dernier commentaire sur RemoteObject / AMF. Si vous utilisez ColdFusion 10; puis les propriétés avec une valeur nulle sur un objet sont supprimées de l'objet côté serveur. Donc, vous devez vérifier l'existence des propriétés avant d'y accéder ou vous obtiendrez une erreur d'exécution.

Vérifiez comme ceci:

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

Il s'agit d'un changement de comportement par rapport à ColdFusion 9; où les propriétés nulles se transformeraient en chaînes vides.


Modifier le 06/12/2013

Puisqu'il y avait une question sur la façon dont les null sont traités, voici un exemple rapide d'application pour montrer comment une chaîne "null" se rapportera au mot réservé 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>

La sortie de trace est:

la chaîne nulle n'est pas égale au mot réservé nul en utilisant la condition! =

la chaîne nulle n'est pas égale au mot réservé nul en utilisant la condition ==

la chaîne nulle n'est pas égale au mot réservé nul en utilisant la condition ===


8
@ Reboog711 Le nom de famille de l'employé est littéralement la chaîne "Null" comme dans "Mon nom est Pat Null" Votre réponse ne parvient pas à transmettre le nom de famille de l'employé. Votre réponse cache simplement le fait que "Null" est contraint de manière inappropriée dans le concept de langage null par la méthode appendChild () comme décrit par Ben Burns. Il en résulte toujours un échec du système à traiter avec M. ou Mme Null.
Maxx Daymon

2
@MaxxDaymon Je pense que vous avez mal interprété ma réponse. Il ne présente pas de solution; mais plutôt une explication de la raison pour laquelle le problème se produit; et cite le code pertinent du Flex Framework. Mon montage plus récent est peut-être mal placé; car il traite d'une approche alternative et n'est pas directement lié à la question d'origine.
JeffryHouser

1
Vous êtes en quelque sorte sur la bonne voie, mais à ce stade du code se contenttrouve la chaîne "null", et "null" == null renvoie false, de sorte que le test se comporte comme prévu. Au lieu de cela, je crois que le problème est un mélange de la façon dont XML.appendChild gère un argument de chaîne et comment un élément XML racine contenant uniquement la chaîne "null" peut être contraint à un littéral null.
Ben Burns

@ Reboog711 Jetez un oeil à mon violon. "null"! = null` le retour trueest le comportement souhaité ici. Si le contraire se produisait, cela éliminerait la chaîne "null" du processus de codage, ce qui serait en fait la cause du problème. Cependant, parce que ce test réussit, l'encodeur continue, jusqu'à ce que XML.appendChild le supprime en raison d'un bogue de coercition.
Ben Burns

4
Pas de soucis. Si vous voulez voir le vrai problème, ajoutez var xml:XML = <root>null</root>; var s:String = (xml == null) ? "wtf? xml coerced to null?!!" : "xml not coerced to null."; trace(s);à votre exemple de code.
Ben Burns

65

Traduisez tous les personnages dans leurs équivalents hexadécimaux. Dans ce cas, Nullserait converti en&#4E;&#75;&#6C;&#6C;


41
Veuillez ne pas faire ça. CDATA a été créé pour être utilisé dans les cas où vous devez échapper à un bloc de texte entier.
Ben Burns

4
Je peux me tromper, mais je ne pense pas que le fait de voter en baisse simplement parce que ce n'était pas votre solution est de savoir comment cela devrait fonctionner. Vous devez également garder à l'esprit que le problème appelle une solution heuristique car il n'y a pas de moyen évident, comme en témoigne la variété des solutions publiées. Enfin, en gardant à l'esprit que je ne connais pas CF, un décodeur n'équivaudrait-il pas simplement au texte interne de <message><!!CDATA[NULL 4,0 /> </message> au texte interne de <message> NULL </ message>? Si oui, alors CDATA est-il vraiment une solution?
doogle

7
J'ai voté contre parce que c'est un anti-modèle. Le bogue dans ce cas n'est pas dans CF, c'est dans ActionScript. Vous soulevez néanmoins un bon point. Je vais ajouter un test à mon violon pour l'encodage CDATA.
Ben Burns

51

La chaîne d'une nullvaleur dans ActionScript donnera la chaîne "NULL". Je soupçonne que quelqu'un a décidé que c'est donc une bonne idée de décoder la chaîne "NULL"car null, provoquant la rupture que vous voyez ici - probablement parce qu'ils passaient des nullobjets et obtenaient des chaînes dans la base de données, alors qu'ils ne voulaient pas cela (alors assurez-vous de vérifier ce genre de bogue aussi).


Oui, il existe un certain nombre de possibilités ici qui nécessiteront plus de débogage pour s'affiner. 1) Le WSDL utilisé ici est-il suffisamment expressif pour faire la distinction entre "NULL" en tant que valeur de chaîne et une valeur null (ou omise) réelle? 2) Si tel est le cas, le client code-t-il correctement le nom de famille (sous la forme d'une chaîne et non d'un littéral nul) 3) Dans l'affirmative, le service interprète-t-il correctement «NULL» comme une chaîne ou le contraint-il à une valeur nulle?
pimlottc

39

En tant que hack, vous pouvez envisager d'avoir une gestion spéciale du côté client, en convertissant la chaîne 'Null' en quelque chose qui ne se produira jamais, par exemple, XXNULLXX et en reconvertissant sur le serveur.

Ce n'est pas joli, mais cela peut résoudre le problème pour un tel cas limite.


32
XXNULLXX pourrait aussi être un nom. Tu ne sais pas. Peut-être que les gens en Indonésie n'ont pas de nom de famille et utilisent une variante de XXX comme nom de famille lorsque cela est nécessaire.
gb.

3
Même concept, mais mettez à jour tous les noms dans la base de données et faites une préface avec du caractère (1Null, 1Smith). Supprimez ce caractère dans le client. Bien sûr, cela pourrait être un travail acarien que la solution de Reboog.
bobpaul

14
@BenBurns Oui, mais que faire si je veux nommer mon enfant &#78;&#117;&#108;&#108;?
Sirènes

@Sirens Ce n'est pas le problème. Si mon nom est "<& quot;>", je m'attends à ce qu'il soit correctement échappé sous la forme & quot; & lt; & amp; quot; & gt; & quot ;, cela va de soi. Le vrai problème est qu'une application se comporte comme si elle utilisait une liste noire pour les noms.
M. Lister

30

Eh bien, je suppose que l'implémentation Flex de l'encodeur SOAP semble sérialiser les valeurs nulles de manière incorrecte. Les sérialiser en tant que String Null ne semble pas être une bonne solution. La version formellement correcte semble passer une valeur nulle comme:

<childtag2 xsi:nil="true" />

Ainsi, la valeur de "Null" ne serait rien d'autre qu'une chaîne valide, ce qui est exactement ce que vous recherchez.

Je suppose que la correction de cela dans Apache Flex ne devrait pas être si difficile à faire. Je recommanderais d'ouvrir un numéro Jira ou de contacter les gars de la liste de diffusion apache-flex. Cependant, cela ne résoudrait que le côté client. Je ne peux pas dire si ColdFusion pourra travailler avec des valeurs nulles encodées de cette façon.

Voir aussi le blog de Radu Cotescu Comment envoyer des valeurs nulles dans les requêtes soapUI .


6
Il y a de bonnes informations ici, donc je ne voterai pas, mais je me suis dit que cela valait la peine d'être commenté. Par défaut, XMLEncoder.as va réellement encoder une vraie nullvaleur correctement, en définissant xsi:nil="true"l'élément. Le problème semble être lié à la manière dont le XMLtype ActionScript lui-même (et non l'encodeur) gère la chaîne "null".
Ben Burns

22

C'est un kludge, mais en supposant qu'il y ait une longueur minimale pour SEARCHSTRING, par exemple 2 caractères, substringle SEARCHSTRINGparamètre au deuxième caractère et passez-le à la place comme deux paramètres: SEARCHSTRING1 ("Nu")et SEARCHSTRING2 ("ll"). Concatenateles remettre ensemble lors de l'exécution de la requête dans la base de données.


32
CDATA a été ajouté à la spécification XML pour éviter ces types de kludges.
Ben Burns

8
Il n'est pas nécessaire d'échapper à "Null" avec CDATA, il n'y a pas de mot-clé null en XML.
2015

6
D'accord avec @eckes. Je ne comprends pas pourquoi on parle autant de CDATA. CDATA n'est utile que pour échapper des caractères qui ont une signification spéciale en XML. aucun de: n, u, lont une sémantique spéciale en XML. "NULL" et "<! [CDATA [NULL]]>" sont identiques à un analyseur XML.
jasonkarns

9
@jasonkarns - Je suis d'accord à 100% qu'il ne devrait y avoir rien de spécial à propos du nœud chaîne / texte NULL, mais être pédant, <blah>null</blah>et <blah><![CDATA[null]]>ne sont pas les mêmes que pour un analyseur XML. Ils devraient produire les mêmes résultats, mais le flux logique pour les gérer est différent. C'est cet effet que nous exploitons comme solution de contournement au bogue dans l'implémentation XML flexible. Je préconise cela par rapport à d'autres approches car il préserve la lisibilité du texte et n'a aucun effet secondaire pour les autres analyseurs.
Ben Burns du
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.