在ActionScript 3中向SOAP Web服务传递“Null”姓氏的解决方案
在ActionScript 3中向SOAP Web服务传递“Null”姓氏的解决方案
技术背景
在开发员工查找应用程序时,遇到了一个特殊问题:有一位员工的姓氏是“Null”,当使用该姓氏作为搜索词时,应用程序会出错。错误信息显示为 <soapenv:Fault>
,具体错误代码为 soapenv:Server.userException
,错误字符串为 coldfusion.xml.rpc.CFCInvocationException: [coldfusion.runtime.MissingArgumentException : The SEARCHSTRING parameter to the getFacultyNames function is required but was not passed in.]
。这里的参数类型为字符串,开发环境使用了WSDL(SOAP)、Flex 3.5、ActionScript 3和ColdFusion 8。需要注意的是,从ColdFusion页面将Web服务作为对象调用时,不会出现此错误。
实现步骤
问题追踪
最初以为是类型转换错误,即 null
被转换为 "null"
,但经过在 wonderfl.net
上的调试和对 mx.rpc.xml.*
代码的跟踪,发现问题出在 XMLEncoder
类的 setValue
方法中。在该方法的第1795行(3.5版本源码),所有的XML编码最终归结为 currentChild.appendChild(xmlSpecialCharsFilter(Object(value)));
,实际上等同于 currentChild.appendChild("null");
。根据测试,这行代码返回一个空的XML元素。
问题原因
根据bug报告 FLEX - 33664
中的评论者 Justin Mclean
的说法,问题的根源在于:当 currentChild.appendChild
接收到字符串 "null"
时,它首先将其转换为一个文本为 null
的根XML元素,然后将该元素与 null
字面量进行弱相等测试。在这个测试中,包含 null
的XML元素被强制转换为 null
类型,或者 null
类型被强制转换为包含字符串 "null"
的根XML元素,导致测试通过,而实际上这个测试应该失败。
解决方案
为了解决这个问题,在修复ActionScript的每个版本中的这个bug之前,唯一合理的解决方法是测试字段是否为 "null"
,并将其转义为CDATA值。CDATA值是处理整个文本值可能导致编码/解码问题的最合适方式,因为它可以保持文本的可读性。
核心代码
以下是一个示例代码,用于演示如何区分字符串 "null"
和保留字 null
:
1 |
|
这段代码的跟踪输出为:
1 |
|
最佳实践
- 使用CDATA转义:在处理可能包含特殊字符串(如
"null"
)的输入时,将其转义为CDATA值,以避免编码问题。 - 严格相等测试:在检查XML或其他数据类型是否为
null
时,尽量使用严格相等测试(===
),以避免弱相等测试带来的意外结果。
常见问题
CDATA是否必要
虽然在XML中,普通的 "NULL"
和 <![CDATA[NULL]]>
在解析上是相同的,但在处理Flex XML实现中的这个bug时,使用CDATA可以作为一种有效的变通方法,因为它可以利用不同的逻辑流程来避免问题,同时保持文本的可读性。
其他解决方案的局限性
- 修改编码器类:修改
mx.rpc.xml.XMLEncoder
类虽然可以解决问题,但需要对Flex框架有深入的了解,并且修改后可能会影响其他部分的功能,维护成本较高。 - 字符编码转换:将所有字符转换为十六进制实体等效物(如
E;KC;C;
)会降低文本的可读性,并且在处理大量数据时效率较低。 - 客户端特殊处理:在客户端将
"Null"
转换为其他字符串(如XXNULLXX
)并在服务器端转换回来,可能会因为该字符串本身也是一个合法的姓氏而导致问题。