【问题标题】:How to pass "Null" (a real surname!) to a SOAP web service in ActionScript 3如何在 ActionScript 3 中将“Null”(一个真正的姓氏!)传递给 SOAP Web 服务
【发布时间】:2011-05-26 06:44:02
【问题描述】:

我们有一位姓 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

我正在使用:

  • WSDL (SOAP)
  • Flex 3.5
  • 动作脚本 3
  • ColdFusion 8

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

【问题讨论】:

标签: apache-flex actionscript soap coldfusion wsdl


【解决方案1】:

追踪它

起初我认为这是一个强制错误,null 被强制转换为 "null" 并且 "null" == null 的测试通过了。它不是。 我很接近,但非常非常错误。对此感到抱歉!

我已经做了很多fiddling on wonderfl.net 并跟踪mx.rpc.xml.* 中的代码。在XMLEncoder 的第 1795 行(在 3.5 源代码中),在setValue 中,所有 XMLEncoding 归结为

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

本质上是一样的:

currentChild.appendChild("null");

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

原因

根据评论者 Justin Mclean 在错误报告 FLEX-33664 上的说法,以下是罪魁祸首(请参阅我的 fiddle 中的最后两个测试来验证这一点):

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 的 XML 被强制为 null 类型,要么 null 类型被强制为包含字符串“null”的根 xml 元素,并且测试通过了它可能失败的地方。一种解决方法可能是在检查 XML(或任何东西,真的)是否“空”时始终使用 strict equality 测试。

解决方案

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

CDATA 值是改变整个文本值的最合适方法,否则会导致编码/解码问题。 例如,十六进制编码适用于单个字符。当您转义元素的整个文本时,首选 CDATA 值。这样做的最大原因是它保持了人类的可读性。

【讨论】:

    【解决方案2】:

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

    从问题中不清楚这是问题的根源,并且鉴于第一个答案的评论中提到的解决方案(将参数嵌入结构中),它似乎可能是其他问题。

    【讨论】:

      【解决方案3】:

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

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

      【讨论】:

      • name="Null" 当然是有用的,我看不出它应该和NaN有什么关系。
      【解决方案4】:

      @doc_180 的概念是正确的,只是他专注于数字,而最初的发帖人则存在字符串问题。

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

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

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

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

      您必须扩展此类以删除验证。然后是一个大雪球,修改 SOAPEncoder 以使用您修改后的 XMLEncoder,然后修改 Operation 以使用您修改后的 SOAPEncoder,然后修改 WebService 以使用您的备用 Operation 类。

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

      您也许可以只修复 XMLEncoder 行并做一些monkey patching 以使用您自己的类。

      我还要补充一点,如果您切换到将 RemoteObject/AMF 与 ColdFusion 一起使用,则 null 可以毫无问题地传递。


      2013 年 11 月 16 日更新

      我在上一条关于 RemoteObject/AMF 的评论中添加了一个最新内容。如果您使用的是 ColdFusion 10;然后从服务器端对象中删除对象上具有空值的属性。因此,您必须在访问之前检查属性是否存在,否则会出现运行时错误。

      像这样检查:

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

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


      2013 年 12 月 6 日编辑

      由于存在关于如何处理空值的问题,这里有一个快速示例应用程序来演示字符串“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>
      

      跟踪输出为:

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

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

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

      【讨论】:

      • @Reboog711 员工的姓氏实际上是字符串“Null”,如“我的名字是 Pat Null” 您的回答未能通过员工的姓氏。您的回答只是隐藏了这样一个事实,即“Null”被 Ben Burns 描述的 appendChild() 方法不恰当地强制转换为 null 的语言概念。结果仍然是系统无法处理Mr.或Ms.Null。
      • @MaxxDaymon 我认为您误解了我的回答实际上是什么。它没有提供解决方案;而是解释为什么会出现问题;并引用 Flex 框架中的相关代码。我最近的编辑可能放错了位置;因为它讨论了一种替代方法,并且与原始问题没有直接关系。
      • 你在正确的轨道上,但在代码content 中的那一点是字符串"null",并且“null” == null 返回 false,因此测试的行为如下故意的。相反,我认为问题在于 XML.appendChild 如何处理字符串参数,以及如何将仅包含字符串“null”的根 XML 元素强制转换为文字 null
      • @Reboog711 看看我的小提琴。 "null" != null` 返回 true 是此处所需的行为。如果发生相反的情况,这将从编码过程中丢弃字符串“null”,这实际上是问题的原因。然而,由于这个测试成功,编码器继续运行,直到 XML.appendChild 由于强制错误而丢弃它。
      • 不用担心。如果您想查看真正的问题,请将var xml:XML = &lt;root&gt;null&lt;/root&gt;; var s:String = (xml == null) ? "wtf? xml coerced to null?!!" : "xml not coerced to null."; trace(s); 添加到您的代码示例中。
      【解决方案5】:

      将所有字符翻译成对应的十六进制实体。在这种情况下,Null 将被转换为 &amp;#4E;&amp;#75;&amp;#6C;&amp;#6C;

      【讨论】:

      • 请不要这样做。创建 CDATA 是为了在需要转义整个文本块的情况下使用。
      • 我可能是错的,但我不认为仅仅因为它不是你的解决方案而投反对票是它应该如何工作的。此外,您必须记住问题需要启发式解决方案,因为没有一种明显的方法,正如发布的各种解决方案所证明的那样。最后,请记住我不知道 CF,解码器不会将 的内部文本等同于 NULL 的内部文本留言>?如果是这样,那么 CDATA 真的是一个解决方案吗?
      • 我投了反对票,因为这是一种反模式。这种情况下的错误不在 CF 中,而是在 ActionScript 中。但是,您仍然提出了一个很好的观点。我将在我的小提琴中添加一个 CDATA 编码测试。
      • 为什么都是字符?一个还不够吗?
      【解决方案6】:

      ActionScript 中的null 值进行字符串化将得到字符串"NULL"。我的怀疑是有人已经决定,因此,将字符串 "NULL" 解码为 null 是一个好主意,这会导致您在此处看到的损坏——可能是因为他们传入了 null 对象并获取了字符串数据库,当他们不想要的时候(所以一定要检查那种错误)。

      【讨论】:

      • 是的,这里有很多可能需要更多调试才能缩小范围。 1) 此处使用的 WSDL 是否足以区分“NULL”作为字符串值和实际的 null(或省略)值? 2) 如果是,客户端是否正确编码姓氏(作为字符串而不是空字面量) 3) 如果是,服务是否将“NULL”正确解释为字符串,或将其强制为空值?跨度>
      【解决方案7】:

      作为一种技巧,您可以考虑在客户端进行特殊处理,将“Null”字符串转换为永远不会发生的内容,例如 XXNULLXX,然后在服务器上转换回。

      它并不漂亮,但它可以解决这种边界情况的问题。

      【讨论】:

      • XXNULLXX 也可以是一个名字。你不知道。也许印度尼西亚人没有姓氏,需要时使用 XXX 的变体作为姓氏。
      • 相同的概念,但更新数据库中的所有名称并在前言中添加一些字符(1Null,1Smith)。剥离客户端中的那个字符。当然,这可能比 Reboog 的解决方案更简单。
      • @BenBurns 是的,但是如果我想给我的孩子取名为 &amp;#78;&amp;#117;&amp;#108;&amp;#108; 怎么办?
      • @Sirens 这不是问题所在。如果我的名字是“,那么我希望它可以正确地转义为“
      【解决方案8】:

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

      <childtag2 xsi:nil="true" />
      

      所以“Null”的值只不过是一个有效的字符串,这正是您要寻找的。​​p>

      我想在 Apache Flex 中解决这个问题应该不会那么难。我建议打开一个 Jira 问题或联系 apache-flex 邮件列表的人。但是,这只会修复客户端。我不能说 ColdFusion 是否能够处理以这种方式编码的空值。

      另请参阅 Radu Cotescu 的博文 How to send null values in soapUI requests

      【讨论】:

      • 这里有很好的信息,所以我不会投反对票,但我认为值得发表评论。默认情况下,通过在元素上设置xsi:nil="true",XMLEncoder.as 实际上会正确编码一个真正的null 值。问题实际上似乎在于 ActionScript XML 类型本身(不是编码器)处理字符串 "null" 的方式。
      【解决方案9】:

      这是一个杂项,但假设 SEARCHSTRING 有一个最小长度,例如 2 个字符,substring 第二个字符处的 SEARCHSTRING 参数并将其作为两个参数传递:SEARCHSTRING1 ("Nu")SEARCHSTRING2 ("ll"). Concatenate 在对数据库执行查询时将它们重新组合在一起。

      【讨论】:

      • CDATA 被添加到 XML 规范中以避免这些类型的混乱。
      • 没有必要用 CDATA 转义“Null”,XML 中没有 null 关键字这样的东西。
      • 同意@eckes。我不明白为什么会有这么多关于 CDATA 的讨论。 CDATA 仅用于转义 XML 中具有特殊含义的字符。没有一个:nul 在 XML 中具有特殊语义。 "NULL" 和 "" 与 XML 解析器相同。
      • @jasonkarns - 我同意 100% 应该 字符串/文本节点 NULL 没有什么特别之处,但要迂腐,&lt;blah&gt;null&lt;/blah&gt;&lt;blah&gt;&lt;![CDATA[null]]&gt;与 XML 解析器不同。它们应该产生相同的结果,但是处理它们的逻辑流程不同。我们正在利用这种效果来解决 flex XML 实现中的错误。我提倡这种方法优于其他方法,因为它保留了文本的可读性,并且对其他解析器没有副作用。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2022-07-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-11-12
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多