在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)并在服务器端转换回来,可能会因为该字符串本身也是一个合法的姓氏而导致问题。