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


我们有一名姓氏为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页面调用Web服务作为对象时发生。


4475
2017-12-16 00:42


起源


它可能对特定问题没有多大帮助,但SOAP 1.2允许可以为空的值,请参阅 w3.org/TR/2001/WD-soap12-20010709/#_Toc478383513 - JensG
我有一种感觉它涉及Dave Null。 - George Gibson
至少它不涉及查克诺里斯。这就是为什么要在代码中远离他: codesqueeze.com/... - SDsolar
员工是否考虑过改名? - Tatranskymedved
参考BBC: bbc.com/future/story/... - biziclop


答案:


 追踪它

起初我以为这是一个强制性的错误 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,然后针对null文字测试该元素。这是一个弱相等性测试,因此将包含null的XML强制转换为null类型,或者将null类型强制转换为包含字符串“null”的根xml元素,并且测试通过它可能失败的地方。一个修复可能是永远使用 严格平等 检查XML(或任何,真的)检查“nullness”。

我能想到的唯一合理的解决方法,就是在每个该死的ActionScript版本中修复这个bug,就是测试字段为“null”和 逃避他们 CDATA值 

CDATA值是改变整个文本值的最合适方式,否则会导致编码/解码问题。 例如,十六进制编码用于单个字符。当您转义元素的整个文本时,首选CDATA值。最大的原因是它保持了人类的可读性。


1049
2017-08-01 17:31





xkcd注意Bobby Tables网站 对于避免在各种语言的SQL查询中对用户数据(在本例中为字符串“Null”)的不正确解释有很好的建议,包括 ColdFusion的

从问题中不清楚这是问题的根源,并且考虑到对第一个答案的评论中指出的解决方案(将参数嵌入到结构中),似乎它可能是其他东西。


286
2018-04-27 20:00





问题可能出在Flex的SOAP编码器中。尝试在Flex应用程序中扩展SOAP编码器并调试程序以查看如何处理null值。我的猜测是,它已经过去了 为NaN (不是数字)。这有时会弄乱SOAP消息解组过程(最值得注意的是) JBoss的 5服务器...)。我记得扩展了SOAP编码器并对NaN的处理方式进行了明确的检查。

(另一方面,如果员工ID为Null,您是否希望做一些有用的事情,这不是验证问题吗?我可能错了,因为我几乎不知道要求......)


235
2018-01-16 08:13



name =“Null”当然很有用,我也不知道它应该如何与NaN相关。 - eckes


@ doc_180有正确的概念,除了他专注于数字,而原始海报有字符串的问题。

解决方案是改变 mx.rpc.xml.XMLEncoder 文件。这是第121行

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

[我查看了Flex 4.5.1 SDK;行号可能在其他版本中有所不同]

基本上,验证失败是因为'content为null',因此您的参数不会添加到传出的SOAP数据包中;从而导致缺少参数错误。

您必须扩展此类以删除验证。然后链上有一个大雪球,修改SOAPEncoder以使用修改后的XMLEncoder,然后修改Operation以使用修改后的SOAPEncoder,然后模拟WebService以使用备用Operation类。

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

您可以只修复XMLEncoder行并进行一些猴子修补以使用您自己的类。

我还要补充一点,如果你切换到使用带有ColdFusion的RemoteObject / AMF,则传递null并没有问题。


2013年11月16日更新

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

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

这是CF9的行为变化;其中null属性将变为空字符串。


编辑12/6/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 string不等于null保留字

使用==条件,null string不等于null保留字

使用===条件,null string不等于null保留字


125
2018-05-03 15:51



@ Reboog711员工的姓氏实际上是字符串“Null”,如“我的名字是Pat Null”你的答案未能通过员工的姓氏。你回答的只是隐藏了这样一个事实:“Null”被Ben Burns所描述的appendChild()方法强制转换为null的语言概念。结果仍然是系统未能与Null先生或Null女士打交道。 - Maxx Daymon
@MaxxDaymon我觉得你误解了我的答案实际上是什么。它没有提出解决方案;而是对问题发生原因的解释;并引用Flex Framework的相关代码。我最近的编辑可能是错误的;因为它讨论了另一种方法,并没有与原始问题直接相关。 - JeffryHouser
你在正确的轨道上,但在代码中的那一点 content 是字符串 "null",并且“null”== null返回false,以便测试按预期运行。相反,我认为问题是XML.appendChild如何处理字符串参数,以及如何将仅包含字符串“null”的根XML元素强制转换为字面值的混合 null。 - Ben Burns
@ Reboog711看看我的小提琴。 “null”!= null`返回 true 在这里是理想的行为。如果相反的情况发生,这将从编码过程中丢弃字符串“null”,这实际上是问题的原因。但是,由于此测试成功,编码器继续运行,直到XML.appendChild由于强制错误而丢弃它。 - Ben Burns
别担心。如果你想看到真正的问题添加 var xml:XML = <root>null</root>; var s:String = (xml == null) ? "wtf? xml coerced to null?!!" : "xml not coerced to null."; trace(s); 到您的代码示例。 - Ben Burns


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


62
2018-04-30 19:03



请不要这样做。创建CDATA是为了在需要转义整个文本块的情况下使用。 - Ben Burns
我可能是错的,但我不认为只是因为事实并非如此 你的 解决方案是它应该如何工作。此外,您必须记住问题需要启发式解决方案,因为没有一种明显的方法,正如所发布的各种解决方案所证明的那样。最后,请记住我不知道CF,解码器不会将<message> <![CDATA [NULL]]> </ message>的内部文本等同于<message> NULL的内部文本</消息>?如果是这样,那么CDATA真的是一个解决方案吗? - doogle
我贬低了因为这是一种反模式。这种情况下的错误不在CF中,而是在ActionScript中。但是,你提出了一个好点。我将为CDATA编码的小提琴添加一个测试。 - Ben Burns


字符串化 null 价值 动作脚本 会给出字符串 "NULL"。我怀疑有人已经决定解码字符串是一个好主意 "NULL" 如 null,导致你在这里看到的破损 - 可能是因为他们正在传递 null 数据库中的对象和获取字符串,当他们不想要它时(所以一定要检查那种错误)。


49
2018-04-28 20:15



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


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

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


36
2018-04-28 08:43



XXNULLXX也可能是一个名字。你不知道。也许印度尼西亚的人没有姓氏,并在需要时使用XXX的姓氏作为姓氏。 - gb.
或者,yanno,总有CDATA ...... - Ben Burns
相同的概念,但更新数据库中的所有名称,然后更新一些字符(1Null,1Smith)。在客户端中删除该角色。当然,这可能比Reboog的解决方案更有效。 - bobpaul
@BenBurns是的,但如果我想给孩子起个名字怎么办? &#78;&#117;&#108;&#108;? - Sirens
@Sirens那不是问题。如果我的名字是“<”>“,那么我希望它能够正确转义为&lt;&amp; quot;&gt;&quot;”,这是不言而喻的。真正的问题是应用程序的行为就像它使用黑名单一样。 - Mr Lister


好吧,我猜Flex的SOAP Encoder实现似乎错误地序列化了空值。将它们序列化为String Null似乎不是一个好的解决方案。正式版本似乎是传递空值为:

<childtag2 xsi:nil="true" />

所以“Null”的值只不过是一个有效的字符串,这正是你要找的。

我想在Apache Flex中修复这个问题不应该那么难。我建议打开一个Jira问题或联系apache-flex邮件列表的人。然而,这只会修复客户端。我不能说ColdFusion是否能够使用这种方式编码的空值。

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


30
2017-07-17 07:56



这里有很好的信息,所以我不会投票,但我认为这值得评论。默认情况下,XMLEncoder.as实际上将编码为true null 正确的价值,通过设置 xsi:nil="true" 在元素上。问题实际上似乎与ActionScript有关 XML type本身(不是编码器)处理字符串 "null"。 - Ben Burns