如何在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

我正在使用:

  • WSDLSOAP
  • flex3.5
  • ActionScript 3
  • ColdFusion 8

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

938914 次浏览

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

我的猜测是,它被传递为NaN(不是数字)。这将在某个时候弄乱SOAP消息解组过程(最明显的是在JBoss 5服务器中…)。我记得扩展了SOAP编码器并对如何处理NaN进行了显式检查。

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

从问题中看不出这是问题的根源,并且考虑到第一个答案的注释中提到的解决方案(将参数嵌入结构中),它似乎可能是别的东西。

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

它并不漂亮,但它可能会解决这样一个边界情况的问题。

这是一个拼凑,但假设SEARCHSTRING有一个最小长度,例如2个字符,substringSEARCHSTRING参数在第二个字符,并将其作为两个参数传递:SEARCHSTRING1 ("Nu")SEARCHSTRING2 ("ll").Concatenate他们一起执行查询时数据库。

字符串脚本操作脚本中的null值将得到字符串"NULL"。我怀疑有人已经决定,因此,将字符串"NULL"解码为null是一个好主意,导致您在这里看到的破坏-可能是因为他们传入null对象并在数据库中获取字符串,当他们不想要的时候(所以一定要检查这种bug)。

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

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

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

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

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

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

您必须扩展这个类以删除验证。然后在链上有一个大雪球,修改SOAPEncoder以使用修改后的XMLEncoder,然后修改操作以使用修改后的SOAPEncoder,然后修改WebService以使用您的替代操作类。

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

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

我还将补充一点,如果您切换到使用带有ColdFusion的Remote teObject/AMF,则会毫无问题地传递null。


11/16/2013更新

我最近添加了一个关于Remote teObject/AMF的评论。如果您使用的是ColdFusion 10;那么对象上具有空值的属性将从服务器端对象中删除。因此,您必须在访问它之前检查属性是否存在,否则您将收到运行时错误。

像这样检查:

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

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


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

跟踪输出为:

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

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

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

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

<childtag2 xsi:nil="true" />

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

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

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

追踪它

起初我以为这是一个强制bug0号被强制到1号,而2号的测试通过了。

从那以后,我做了很多摆弄wonderfl.net和跟踪mx.rpc.xml.*中的代码。在XMLEncoder的第1795行(在3.5源代码中),在setValue中,所有的XMLEncode归结为

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

这基本上是相同的:

currentChild.appendChild("null");

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

原因

根据评论者贾斯汀麦克莱恩在bug报告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(或任何东西,真的)是否为“nullness”时始终使用严格平等测试。

解决方案

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

例如,十六进制编码是针对单个字符的。当您转义元素的整个文本时,CDATA值是首选。这样做的最大原因是它保持了人类的易读性。