我们有一位姓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)柔性3.5动作脚本3冷聚变8

请注意,当从ColdFusion页面作为对象调用Web服务时,不会发生错误。


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

我猜,它是以NaN(不是数字)的形式传递的。这有时会打乱SOAP消息解组过程(尤其是在JBoss 5服务器中…)。我记得扩展了SOAP编码器,并对NaN的处理方式进行了显式检查。


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

从这个问题中还不清楚这是问题的根源,并且考虑到第一个答案的注释中提到的解决方案(将参数嵌入到结构中),这很可能是其他问题。


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

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


这是一个杂烩,但假设SEARCHSRING有一个最小长度,例如2个字符,在第二个字符处对SEARCHSTRING参数进行子串,并将其作为两个参数传递:SEARCHSSTRING1(“Nu”)和SEARCHSTRING2(“ll”)。在对数据库执行查询时,将它们重新连接在一起。


在ActionScript中对空值进行字符串化将得到字符串“null”。我的怀疑是,有人认为,因此,将字符串“NULL”解码为NULL是一个好主意,这会导致您在这里看到的破坏——可能是因为他们在传递NULL对象并在数据库中获取字符串,而他们不想这样做(所以也要确保检查这种错误)。


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


@doc180有正确的概念,只是他专注于数字,而最初的海报有字符串的问题。

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

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

(我查看了Flex 4.5.1 SDK;其他版本的行号可能不同。)

基本上,验证失败是因为“content为null”,因此您的参数没有添加到传出的SOAP数据包中;从而导致丢失的参数错误。

您必须扩展该类以删除验证。然后是一个巨大的滚雪球,修改SOAPEncoder以使用修改的XMLEncoder,然后修改Operation以使用修改后的SOAPEncode器,然后修改WebService以使用替换的Operation类。

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

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

我还要补充一点,如果您切换到使用RemoteObject/AMF和ColdFusion,则传递null时不会出现问题。


2013年11月16日更新:

我在上次关于RemoteObject/AMF的评论中又增加了一条。如果您正在使用ColdFusion 10;然后从服务器端对象中删除对象上具有null值的财产。因此,在访问财产之前,必须检查它是否存在,否则会出现运行时错误。

检查如下:

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

这是ColdFusion 9的行为变化;其中空财产将变成空字符串。


2013年6月12日编辑

由于有一个关于如何处理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>

跟踪输出为:

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


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

<childtag2 xsi:nil="true" />

因此,“Null”的值只不过是一个有效字符串,这正是您要查找的。

我想在ApacheFlex中修复这个问题应该不难。我建议打开Jira问题或联系apacheflex邮件列表中的人。然而,这只会修复客户端。我不能说ColdFusion是否能够处理这样编码的空值。

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


追踪它

起初,我认为这是一个强制错误,其中null被强制为“null”,并且通过了“null”==null的测试。事实并非如此。我很接近,但非常非常错误。抱歉!

此后,我在wonderfl.net上做了很多手脚,并在mx.rpc.xml.*中跟踪代码。在XMLEncoder(在3.5源代码中)的1795行,在setValue中,所有XMLEncoding归结为

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

其基本上与:

currentChild.appendChild("null");

根据我最初的想法,这段代码返回一个空的XML元素。但为什么?

原因

根据评论者贾斯汀·麦克林(Justin Mclean)对错误报告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”时,它首先将其转换为文本为null的根XML元素,然后根据null文本测试该元素。这是一个弱相等测试,因此,要么将包含null的XML强制为null类型,要么将null类型强制为包含字符串“null”的根XML元素,然后测试在可能失败的地方通过。一个解决办法可能是在检查XML(或任何东西)是否为“空”时始终使用严格的相等测试

解决方案除了在每个该死的ActionScript版本中修复这个bug之外,我能想到的唯一合理的解决方法是测试字段是否为“null”,并将其转义为CDATA值。

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