如何在ActionScript 3中将“Null”(真正姓氏!)传递给SOAP Web服务?
我们有一个姓氏为空的员工。 我们的员工查找应用程序在使用该姓氏作为search词时(这种情况经常发生)被杀死。 收到的错误(谢谢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>
可爱,是吧?
参数types是string
。
我在用:
- WSDL(SOAP)。
- Flex 3.5
- ActionScript 3
- ColdFusion 8
请注意,从ColdFusion页面调用webservice作为对象时,错误不会发生。
跟踪它
起初我以为这是一个强制错误, null
被强制为"null"
并且"null" == null
的testing正在通过。 不是。 我很接近,但非常非常错误。 对于那个很抱歉!
我已经在wonderfl.net上做了大量的工作,并通过mx.rpc.xml.*
的代码进行跟踪。 在XMLEncoder
(在3.5源代码)的1795行,在setValue
,所有的XMLEncoding归结为
currentChild.appendChild(xmlSpecialCharsFilter(Object(value)));
这基本上是一样的:
currentChild.appendChild("null");
这个代码,根据我原来的小提琴,返回一个空的XML元素。 但为什么?
原因
根据Justin Mclean在错误报告FLEX-33664上的评论,以下是罪魁祸首(请参阅我的小提琴中的最后两个testing,validation这一点):
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
传递string"null"
,它首先将其转换为一个null
文本根XML元素,然后根据null文本testing该元素。 这是一个弱的等式testing,所以包含null的XML被强制为nulltypes,或者将nulltypes强制转换为包含string“null”的根xml元素,然后testing通过可能会失败的位置。 一个修补程序可能是在检查XML(或者其他任何东西)时总是使用严格的相等性testing来检查“无效性”。
解
我能想到的唯一合理的解决方法就是在每个该死的ActionScript版本中修复这个bug,就是testing字段为“null”并将它们作为CDATA值转义。
CDATA值是改变整个文本值的最合适的方式,否则会导致编码/解码问题。 hex编码,例如,是为了个别字符。 当您转义元素的整个文本时,首选CDATA值。 最大的原因是它保持了人的可读性。
在xkcd说明中 , Bobby Tables网站提供了很好的build议,可以避免在各种语言的SQL查询(包括ColdFusion )中错误地解释用户数据(在本例中为string“Null”)。
从这个问题不清楚,这是问题的根源,并且在第一个答案(将参数embedded到结构中)的评论中给出了解决scheme中提到的解决scheme,似乎可能是其他问题。
这个问题可能在Flex的SOAP编码器中。 尝试在Flex应用程序中扩展SOAP编码器,并debugging程序以查看如何处理空值。 我的猜测是,它是作为NaN (不是数字)传递的。 这会在某个时候搞乱SOAP消息解组过程(特别是在JBoss 5服务器中)。 我记得扩展了SOAP编码器,并且明确地检查了如何处理NaN。
(在附注中,如果员工ID是Null,你是否希望做一些有用的事情?这不是一个validation问题吗?我可能是错的,因为我几乎不知道需求…)
@ doc_180有正确的概念,除了他专注于数字,而原始的海报有string的问题。
解决方法是更改mx.rpc.xml.XMLEncoder
文件。 这是121线
if (content != null) result += content;
[我看了一下Flex 4.5.1 SDK; 行号可能在其他版本中有所不同]
基本上,validation失败,因为“内容为空”,因此您的参数不会添加到传出的SOAP数据包; 从而导致缺less参数错误。
你必须扩展这个类来删除validation。 然后在链中出现一个巨大的雪球,修改SOAPEncoder以使用您的修改的XMLEncoder,然后修改Operation以使用您的修改的SOAPEncoder,然后将WebService模糊化以使用您的替代操作类。
我花了几个小时,但需要继续前进。 这可能需要一两天的时间。
你可能只能修复XMLEncoder行,并做一些猴子修补来使用你自己的类。
我还要补充的是,如果您切换到使用ColdFusion的RemoteObject / AMF,空传递没有问题。
11/16/2013更新 :
最近我还有一个关于RemoteObject / AMF的评论。 如果你正在使用CF10; 那么对象上的空值属性将从服务器端对象中删除。 所以,在访问它之前你必须检查属性的存在,否则你会得到一个运行时错误。 像这样检查:
<cfif (structKeyExists(arguments.myObject,'propertyName')> <!--- no property code ---> <cfelse> <!--- handle property normally ---> </cfif>
这是从CF9行为的变化; 空属性将变成空string。
编辑12/6/2013
由于存在一个关于空值如何处理的问题,因此是一个快速示例应用程序,用于演示如何将string“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 (eg, services, value objects) here --> </fx:Declarations> </s:Application>
跟踪输出是:
空string不等于使用!=条件的空保留字
空string不等于使用==条件的空保留字
空string不等于使用===条件的空保留字
将所有的字符转换为它们的hex实体。 在这种情况下, Null
将被转换为E;KC;C;
在ActionScript中对null
值进行string化将会给出string"NULL"
。 我怀疑是有人已经决定,把string"NULL"
解码为null
是一个好主意,这会导致你在这里看到的破坏 – 可能是因为它们传入null
对象并在数据库中获取string,他们不希望这样(所以一定要检查那种错误)。
作为一个黑客,你可以考虑在客户端进行一些特殊的处理,将“Null”string转换为永远不会出现的string,例如XXNULLXX,然后转换回服务器端。
这不是很好,但是可以解决这个边界案例的问题。
那么,我猜Flex编码器的Flex实现似乎不正确地序列化空值。 将它们串行化为一个String Null似乎不是一个好的解决scheme。 正式的正确版本似乎是传递一个空值作为:
<childtag2 xsi:nil="true" />
所以“Null”的值就是有效的string,这正是你正在寻找的。
我想这个固定在Apache Flex中不应该很难完成。 我会build议打开一个Jira问题或联系apache-flex邮件列表的人。 但是这只能解决客户端问题。 我不能说如果ColdFusion将能够使用这种方式编码的空值。
另请参阅Radu Cotescu的博客文章如何在soapUI请求中发送空值 。
这是一个混乱,但假设有一个最小长度的SEARCHSTRING
,例如2个字符,在第二个字符的SEARCHSTRING
参数的substring
,并将其作为两个参数: SEARCHSTRING1 ("Nu")
和SEARCHSTRING2 ("ll").
将查询执行到数据库时将它们Concatenate
在一起。