如何在ActionScript 3中将“ Null”(真实的姓氏!)传递给SOAP Web服务


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

我在用:

  • WSDLSOAP
  • Flex 3.5
  • 动作脚本3
  • ColdFusion 8

请注意,从ColdFusion页面将Webservice作为对象调用时,不会发生该错误。


6
它可能对特定问题没有太大帮助,但是SOAP 1.2允许使用可为空的值,请参阅w3.org/TR/2001/WD-soap12-20010709/#_Toc478383513
JensG 2014年

6
我觉得这涉及到Dave Null。
乔治·吉布森

2
至少它不涉及Chuck Norris。这就是在代码中远离他的原因: codequeeze.com/…–
SDsolar

42
员工是否考虑过改名?
Tatranskymedved

11
他应该真正考虑购买Pointer狗并将其称为NullPointer。
安东尼奥·阿尔瓦雷斯

Answers:


1108

追踪

起初我以为这是一个强制性错误,null正在被强制"null"并且通过了测试"null" == null。不是。我很近,但是非常非常错误。对于那个很抱歉!

从那以后,我已经对wonderfl.net进行了很多摆弄,在中查找了代码mx.rpc.xml.*。在XMLEncoder(在3.5源中)的第1795行,在中setValue,所有XMLEncoding都归结为

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

本质上与以下内容相同:

currentChild.appendChild("null");

根据我的原始提琴,此代码返回一个空的XML元素。但为什么?

原因

根据关于bug报告FLEX-33664的评论员Justin Mclean 的介绍,以下是罪魁祸首(请参阅我的小提琴中的最后两个测试来验证这一点):

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",它将首先将其转换为带有text的根XML元素null,然后针对null文字对该元素进行测试。这是一个弱等式测试,因此将包含null的XML强制转换为null类型,或者将null类型强制转换为包含字符串“ null”的根xml元素,并且该测试通过,可能会失败。一种解决方法是在检查XML(或其他任何东西)是否为“空”时始终使用严格的相等性测试。

除了在每个可恶的ActionScript版本中修复此错误之外,我能想到的唯一合理的解决方法是测试字段是否为“ null”并将其作为CDATA值进行转义。

CDATA值是变异整个文本值的最合适方法,否则将导致编码/解码问题。例如,十六进制编码是针对单个字符的。在转义元素的整个文本时,首选CDATA值。这样做的最大原因是它保持了人类可读性。


298

xkcd注释上Bobby Tables网站提供了很好的建议,以避免在各种语言(包括ColdFusion)的SQL查询中避免对用户数据(在这种情况下为字符串“ Null”)进行不正确的解释。

从问题中尚不清楚这是否是问题的根源,考虑到对第一个答案的注释中指出的解决方案(将参数嵌入结构中),似乎还有其他原因。


239

问题可能出在Flex的SOAP编码器中。尝试在Flex应用程序中扩展SOAP编码器并调试程序,以了解如何处理null值。

我的猜测是,它以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,然后将Operation修改为使用修改后的SOAPEncoder,然后将WebService修改为使用备用Operation类。

我花了几个小时,但我需要继续前进。可能需要一两天。

您也许可以修复XMLEncoder行,并进行一些猴子修补程序以使用您自己的类。

我还要补充一点,如果您切换到将RemoteObject / AMF与ColdFusion一起使用,则可以毫无问题地传递null。


2013年11月16日更新

我最近对RemoteObject / AMF的评论中还有一个新内容。如果您使用的是ColdFusion 10;然后将对象上具有空值的属性从服务器端对象中删除。因此,您必须在访问属性之前检查属性是否存在,否则会遇到运行时错误。

像这样检查:

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

与ColdFusion 9相比,这是行为上的变化;null属性将变成空字符串。


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

跟踪输出为:

空字符串不等于使用!=条件的空保留字

空字符串不等于使用==条件的空保留字

空字符串不等于使用===条件的空保留字


8
@ Reboog711员工的姓氏实际上是字符串“ Null”,例如“我的名字叫Pat Null”。您的答案无法传递员工的姓氏。您的回答只是掩盖了一个事实,即Ben Burns所描述的appendChild()方法将“ Null”不适当地强制为null的语言概念。结果仍然是系统无法处理Null先生或女士。
Maxx Daymon

2
@MaxxDaymon我认为您误解了我的答案实际上是什么。它没有提出解决方案。而是解释问题发生的原因;并引用Flex框架中的相关代码。我最近的编辑可能放错了位置;因为它讨论了另一种方法,并且与原始问题没有直接关系。
JeffryHouser

1
您处于正确的轨道上,但是此时代码中content是字符串"null",并且“ null” == null返回false,因此测试的行为符合预期。相反,我认为问题在于XML.appendChild如何处理字符串参数,以及如何仅将包含字符串“ null”的根XML元素强制转换为文字null
Ben Burns

@ Reboog711看我的小提琴。“ null”!= null` true此处需要返回行为。如果发生相反的情况,则这将从编码过程中丢弃字符串“ null”,这实际上就是问题的原因。但是,因为此测试成功,所以编码器继续进行下去,直到XML.appendChild由于强制错误而放弃它为止。
本·伯恩斯2013年

4
别担心。如果您想看到真正的问题,请添加var xml:XML = <root>null</root>; var s:String = (xml == null) ? "wtf? xml coerced to null?!!" : "xml not coerced to null."; trace(s);到您的代码示例中。
本·伯恩斯2013年

65

将所有字符转换为其等效的十六进制实体。在这种情况下,Null将转换为&#4E;&#75;&#6C;&#6C;


41
请不要这样做。创建CDATA是为了在需要转义整个文本块的情况下使用。
Ben Burns 2013年

4
我可能是错的,但我不认为仅仅因为它不是您的解决方案才能发挥作用而就投票否决。另外,您还必须牢记问题需要启发式解决方案,因为没有一种显而易见的方法,如张贴的各种解决方案所表明的那样。最后,请记住,我不知道CF,解码器不会只将<message> <![CDATA [NULL]]> </ message>的内部文本等同于<message> NULL的内部文本</讯息>?如果是这样,那么CDATA真的是一个解决方案吗?
doogle 2013年

7
我拒绝投票,因为这是一种反模式。这种情况下的错误不在CF中,而在ActionScript中。但是,您仍然提出了一个好要点。我将为CDATA编码添加一个测试。
本·伯恩斯

51

nullActionScript中对值进行字符串化将得到字符串"NULL"。我的怀疑是,有人认为将字符串解码"NULL"null,是一个好主意,从而导致您在此处看到损坏—可能是因为他们在null不需要时传递了对象并在数据库中获取了字符串这样(因此也请务必检查这种错误)。


是的,这里有很多可能性,需要进行更多调试才能缩小范围。1)这里使用的WSDL是否具有足够的表达能力,可以区分作为字符串值的“ NULL”和实际的null(或省略)值?2)如果是,则客户端是否正确编码了姓氏(作为字符串,而不是null文字)3)如果是,服务是否正确地将“ NULL”解释为字符串,或将其强制为null值?
pimlottc

39

作为一种黑客,您可以考虑在客户端进行特殊处理,将“ Null”字符串转换为永远不会发生的内容,例如XXNULLXX,然后在服务器上进行转换。

它不是很漂亮,但是可以解决这种边界情况的问题。


32
XXNULLXX也可以是一个名称。你不知道 也许印度尼西亚的人没有姓,需要时可以使用XXX的变体作为姓。
gb。

3
相同的概念,但是使用一些字符(1Null,1Smith)更新数据库中的所有名称和序言。在客户端中剥离该字符。当然,这可能比Reboog的解决方案要小。
bobpaul

14
@BenBurns是的,但是如果我想给我的孩子起名字&#78;&#117;&#108;&#108;怎么办?
警报器

@Sirens那不是问题。如果我的名字是“ <”,那么我希望它可以正确地转义为“&lt;&amp;”,这不用说。真正的问题在于应用程序的行为,好像它使用黑名单来命名一样。
李斯特先生,

30

好吧,我想Flex的SOAP编码器实现似乎错误地序列化了空值。将它们序列化为String Null似乎不是一个好的解决方案。形式上正确的版本似乎要传递一个null值,例如:

<childtag2 xsi:nil="true" />

因此,“ Null”的值就是有效字符串,这正是您要寻找的。

我猜想在Apache Flex中解决此问题并不难。我建议打开一个Jira问题或与apache-flex邮件列表的人联系。但是,这只会修复客户端。我不能说ColdFusion是否能够使用以这种方式编码的空值。

另请参见Radu Cotescu的博客文章如何在soapUI请求中发送空值


6
这里有很好的信息,所以我不会拒绝投票,但我认为值得一提。默认情况下,null通过设置xsi:nil="true"元素,XMLEncoder.as实际上将正确地编码一个真值。实际上,问题似乎出在ActionScript XML类型本身(而非编码器)处理string的方式上"null"
本·伯恩斯

22

这是一个组装机,但假设有一个最小长度SEARCHSTRING,例如2个字符,substring所述SEARCHSTRING:在所述第二特征参数,并将其传递作为两个参数,而不是SEARCHSTRING1 ("Nu")SEARCHSTRING2 ("ll"). Concatenate执行查询数据库时他们回到一起。


32
CDATA已添加到XML规范中,以避免这些类型的冲突。
本·伯恩斯

8
不需要使用CDATA来转义“ Null”,在XML中没有诸如null关键字之类的东西。
eckes 2015年

6
同意@eckes。我不明白为什么这么讲CDATA。CDATA仅用于转义在XML中具有特殊含义的字符。没有的:nul在XML中有特殊的语义。“ NULL”和“ <![CDATA [NULL]]>”与XML解析器相同。
jasonkarns

9
@jasonkarns-我同意100%的意见,关于字符串/文本节点应该没有什么特别的NULL,但是应该是书呆子,<blah>null</blah>并且<blah><![CDATA[null]]>与XML解析器并不相同。它们产生相同的结果,但是处理它们的逻辑流程不同。我们正利用这种效果来解决Flex XML实现中的错误。与其他方法相比,我主张这样做,因为它保留了文本的可读性,并且对其他解析器没有副作用。
本·伯恩斯2015年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.