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

时间:2010-12-16 00:42:14

标签: flex actionscript soap coldfusion wsdl

我们有一名姓氏为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服务作为对象时,会出现错误

9 个答案:

答案 0 :(得分:1081)

追踪

起初我认为这是一个强制性错误,null被强迫"null"并且"null" == null的测试正在通过。不是。 我很亲密,但非常非常错。对此感到抱歉!

我已经完成了很多fiddling on wonderfl.net并追踪mx.rpc.xml.*中的代码。在XMLEncoder的第1795行(在3.5来源中),在setValue中,所有XMLEncoding归结为

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

基本上与:

相同
currentChild.appendChild("null");

根据我原来的小提琴,这段代码返回一个空的XML元素。但为什么呢?

原因

根据评论者Justin Mclean的错误报告FLEX-33664,以下是罪魁祸首(请参阅我的fiddle中的最后两项测试来验证这一点):

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"时,它首先将其转换为带有文本null的根XML元素,然后针对空文字测试该元素。这是一个弱的相等性测试,因此要么将包含null的XML强制转换为null类型,要么将null类型强制转换为包含字符串“null”的根xml元素,并且测试通过它可能失败的地方。一个修复可能是在检查XML(或任何真正的)“nullness”时始终使用strict equality测试。

解决方案

我能想到的唯一合理的解决方法,就是在每个该死的ActionScript版本中修复这个错误,就是测试“null”字段和将它们作为CDATA values转义。

< / p>

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

答案 1 :(得分:293)

xkcd note上,Bobby Tables website提供了很好的建议,可以避免在各种语言的SQL查询中对用户数据的不正确解释(在本例中为字符串“Null”),包括{{3} }}

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

答案 2 :(得分:236)

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

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

答案 3 :(得分:126)

@ 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进行moidfying以使用备用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属性将变为空字符串。


编辑2013年12月6日

由于存在关于如何处理空值的问题,因此这是一个快速示例应用程序,用于演示字符串“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>

跟踪输出为:

  

使用!= condition

,null string不等于null保留字      

使用== condition

,null string不等于null保留字      

使用=== condition

,null string不等于null保留字

答案 4 :(得分:63)

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

答案 5 :(得分:50)

ActionScript中对null值进行字符串化会得到字符串"NULL"。我怀疑有人已经决定将字符串"NULL"解码为null是一个好主意,导致你在这里看到破损 - 可能是因为他们传入{{1}对象和数据库中的字符串,当他们不想要它时(所以一定要检查那种bug)。

答案 6 :(得分:37)

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

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

答案 7 :(得分:30)

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

<childtag2 xsi:nil="true" />

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

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

另见Radu Cotescu的博客文章 How to send null values in soapUI requests

答案 8 :(得分:21)

这是一个kludge,但假设SEARCHSTRING的最小长度,例如2个字符,substring第二个字符的SEARCHSTRING参数,并将其作为两个参数传递:{ {1}}和SEARCHSTRING1 ("Nu") SEARCHSTRING2 ("ll").在执行查询到数据库时将它们重新组合在一起。