在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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
<?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>

这段代码的跟踪输出为:

1
2
3
null string is not equal to null reserved word using the != condition
null string is not equal to null reserved word using the == condition
null string is not equal to null reserved word using the === condition

最佳实践

  • 使用CDATA转义:在处理可能包含特殊字符串(如 "null")的输入时,将其转义为CDATA值,以避免编码问题。
  • 严格相等测试:在检查XML或其他数据类型是否为 null 时,尽量使用严格相等测试(===),以避免弱相等测试带来的意外结果。

常见问题

CDATA是否必要

虽然在XML中,普通的 "NULL"<![CDATA[NULL]]> 在解析上是相同的,但在处理Flex XML实现中的这个bug时,使用CDATA可以作为一种有效的变通方法,因为它可以利用不同的逻辑流程来避免问题,同时保持文本的可读性。

其他解决方案的局限性

  • 修改编码器类:修改 mx.rpc.xml.XMLEncoder 类虽然可以解决问题,但需要对Flex框架有深入的了解,并且修改后可能会影响其他部分的功能,维护成本较高。
  • 字符编码转换:将所有字符转换为十六进制实体等效物(如 &#4E;&#75;&#6C;&#6C;)会降低文本的可读性,并且在处理大量数据时效率较低。
  • 客户端特殊处理:在客户端将 "Null" 转换为其他字符串(如 XXNULLXX)并在服务器端转换回来,可能会因为该字符串本身也是一个合法的姓氏而导致问题。

在ActionScript 3中向SOAP Web服务传递“Null”姓氏的解决方案
https://119291.xyz/posts/2025-04-17.solution-to-pass-null-surname-to-soap-service-in-actionscript3/
作者
ww
发布于
2025年4月17日
许可协议