【问题标题】:SOAP-ERROR: Encoding: Violation of encoding rules?SOAP-ERROR:编码:违反编码规则?
【发布时间】:2010-11-21 12:32:21
【问题描述】:

伙计们,我被困住了,在过去的几个小时里,我的头从桌子上撞了下来。

我正在尝试使用一项服务,并且我调用了 8 个其他函数,这些函数在本质上与这个函数几乎相同,但是这个函数会导致“SOAP-ERROR: Encoding: Violation of encoding rules”错误.

以下是函数调用(出于安全考虑,省略了wsdl):

    function CanLoadProduct($data){

    $client = new SoapClient('wsdl-url');

    $params = array('username'   => $this->username,
                    'password'  => $this->password,
                    'prod'      => $data['productid'],
                    'mdn'       => $data['mdn']);

    try {
        $reply = $client->__soapCall("CanLoadProduct", $params);
    } catch (Exception $e) {
        echo 'Error: ',  $e->getMessage(), "\n";
        print_r($params);
        die();
    }

    if( $reply['result'] == 1 ){
        return TRUE;        // 1 = true
    } else {
        return FALSE;
    }

}

好的,这个函数,连接到一个网络服务,需要的元素是: 用户名、密码、prod、mdn,所有这 4 个都是我作为 $params 数组的一部分提供的。用户名/密码已在前面定义,并且工作正常,因为其他 8 个函数使用 Web 服务没有任何问题。

$data[] 数组(我传递给函数)包含: $data['productid'] $数据['mdn'] 没有使用其他任何东西。

我来了

SOAP-ERROR: Encoding: Violation of encoding rules

出于某种无法解释的原因,谷歌搜索这个错误让我无处可去。还有其他人遇到这个吗?运行 PHP 5.2.9-2。奇怪的是,这与这个 100% 有效的功能相同:

    function GetPIN($productid){

    $client = new SoapClient('wsdl-url');

    $params = array('username'  => $this->username,
                    'password'  => $this->password,
                    'prod'      => $productid);

    try {
        $reply = $client->__soapCall("GetPIN", $params);
    } catch (Exception $e) {
        echo 'Error: ',  $e->getMessage(), "\n";
        die();
    }
        return $reply;
}

这是 WSDL(应该先发布):

<?xml version="1.0" encoding="ISO-8859-1"?>
<definitions xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" 
    xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" 
    xmlns:tns="ready:test" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" 
    xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" 
    xmlns="http://schemas.xmlsoap.org/wsdl/" targetNamespace="ready:test">
<types>
<xsd:schema targetNamespace="ready:test"
>
 <xsd:import namespace="http://schemas.xmlsoap.org/soap/encoding/" />
 <xsd:import namespace="http://schemas.xmlsoap.org/wsdl/" />
</xsd:schema>
</types>
<message name="CanLoadProductRequest">
  <part name="username" type="xsd:string" />
  <part name="password" type="xsd:string" />
  <part name="prod" type="xsd:string" />    
  <part name="mdn" type="xsd:string" />
  <part name="esn" type="xsd:string" /></message>
<message name="CanLoadProductResponse">
  <part name="result" type="xsd:int" /></message>
<portType name="CanLoadProductPortType">
  <operation name="CanLoadProduct">
    <input message="tns:CanLoadProductRequest"/>
    <output message="tns:CanLoadProductResponse"/>
  </operation>
</portType>

<binding name="CanLoadProductBinding" type="tns:CanLoadProductPortType">
  <soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/>
  <operation name="CanLoadProduct">
    <soap:operation soapAction="{url-removed}" style="rpc"/>
    <input>
        <soap:body use="encoded" namespace="" 
           encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>
    </input>
    <output>
        <soap:body use="encoded" namespace="" 
            encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>
    </output>
  </operation>
</binding>
<service name="CanLoadProduct">
  <port name="CanLoadProductPort" binding="tns:CanLoadProductBinding">

    <soap:address location="{url-removed}"/>
  </port>
</service>
</definitions>

【问题讨论】:

  • 如果这是一个 .NET 客户端,我会尝试将“prod”和“mdn”硬编码为已知良好的值,然后看看会发生什么。如果可行,我会一次删除一个硬代码,看看哪个是问题所在。然后我会查看失败的值,看看它是否有什么特别之处。
  • 这也是我的第一个想法。
  • 我尝试对其进行硬编码,但得到相同的结果,非常奇怪。我不知道任何其他解决此问题的方法。
  • 有趣。我认为接下来我想做的是查看 WSDL,然后尝试使用不同的语言(如 Java 或 C#)创建类似的客户端。事实上,在充分尊重“脚本”语言的情况下,我会确保另一种语言具有更多工具支持等。我只会尝试实现一个调用。看看它是否有效会很有趣。
  • 我已经包含了 WSDL,抱歉应该早点完成。

标签: php xml soap


【解决方案1】:

我遇到了同样的问题...但我找到了原因。

  • 首先,我尝试使用 PHP 7.3 或 7.4 或 8.0 的 SoapClient,它可以工作。
  • 其次,我用 PHP 7.2 尝试了 SoapClient(相同的代码),它不起作用。

解决方案:更改PHP版本时,删除wsdl缓存:rm /tmp/wsdl*

【讨论】:

    【解决方案2】:

    我通过将 PHP 版本从 7.2 更改为 7.3 解决了问题(SOAP-ERROR: Encoding: Violation of encoding rules)

    【讨论】:

      【解决方案3】:

      如果您将 PHP 版本升级到 7.3 或更高版本,之前的 WSDL 缓存可能会停止工作。

      默认安装目录是/tmpdisabling cache or deleting the wsdl* cache files 应该可以解决问题。我建议清除缓存,否则您的服务器每次都会拉取 WSDL(这可能是不可取的)。

      【讨论】:

        【解决方案4】:

        在进行单元测试时,我在 PhpStorm 中遇到了这个问题。我禁用了 wsdl 缓存并且它起作用了:

        ini_set("soap.wsdl_cache_enabled", "0");
        

        【讨论】:

          【解决方案5】:

          类似于@bezz,我的问题也是由缓存在临时目录中的 WSDL 引起的。

          我清除了 /tmp 中的 wsdl-* 文件,它起作用了。

          【讨论】:

            【解决方案6】:

            我遇到了同样的问题,并设法通过更正 WSDL 来解决它,它假设服务器会发送一个特定值的整数,但实际上发送的是一个字符串。可能从以下位置修改 WSDL:

            <part name="result" type="xsd:int" /></message>
            

            <part name="result" type="xsd:string" /></message>
            

            可能会解决您的问题,以下是我所面临的特定案例的一些信息:https://blog.dotnetframework.org/2016/12/06/uncaught-soapfault-exception-sender-soap-error-encoding-violation-of-encoding-rules/

            【讨论】:

              【解决方案7】:

              我在使用 SoapUI 工具时遇到了这个错误,直到我用真实的测试数据重新格式化了响应,而不仅仅是“?”。同样使用 SoapUI,响应可能超出预期,并且可能必须通过删除几个可选响应参数来缩短到预期响应。希望这会有所帮助?

              【讨论】:

              • 这也是我的问题。它期望返回一个整数,显然?不是整数。
              • 我怎么知道预期返回什么值?
              【解决方案8】:

              我遇到了同样的问题。

              在soapUI首选项中,我检查了选项首选项→编辑器设置→验证响应,我收到了以下信息:

              第 3027 行:无效的十进制值:意外的字符 '44'。

              这解决了我的问题。字段包含错误的类型值。

              【讨论】:

              • 这对我调试 wsdl 有很大帮助。
              • 首选项位于“文件”下,您还可以打开“验证请求”以查看您是否在测试示例中提交了错误类型的数据。
              【解决方案9】:

              我遇到了同样的问题,我使用__soapCall 的这种语法解决了:

              ...
              $params = new SoapParam($data, 'parameters');
              
              $response = $this->__soapCall('methodName', 
                  array(new SoapVar($data, XSD_ANYTYPE, 'parameters'))
                );        
              ...
              

              代替

              __soapCall('methodName', array($params)
              

              【讨论】:

                【解决方案10】:
                <![CDATA[<?xml version="1.0"
                encoding="utf-8"?>
                <CONTENTXML></CONTENTXML]]></xmlCallString>]]>
                

                【讨论】:

                  【解决方案11】:

                  PHP 中还有一种错误,错误的类型会导致无法将正确的 SOAPfault 返回给客户端。

                  http://bugs.php.net/bug.php?id=50547

                  【讨论】:

                    【解决方案12】:

                    尝试将 XML 作为参数传递给我的一个 Web 服务时,我遇到了同样的问题。在&lt;![CDATA[ ... ]]&gt; 中包装 XML 数据消除了 SOAP-ERROR: Encoding: Violation of encoding rules 并且一切正常。

                    其他详情:
                    1.参数也定义为xsd:string。
                    2. WSDL 是文档/文字。
                    3. 在 php 5.2.10 中使用内置的 SOAP 类。

                    【讨论】:

                      【解决方案13】:

                      看起来您在某处存在类型不匹配,可能是在组装您的请求时(其中一个参数不是字符串类型),或者服务器返回的不是 int(违反 WSDL 响应定义,从而导致客户端认为响应无效,因为它期望其他内容)。

                      • 要测试第一种情况,请确保首先将所有参数转换为字符串
                      • 要测试第二种情况,请创建您的 SoapClient,并将 trace 选项设置为 true,以便之后通过 $client->__getLastResponse() 从服务器访问实际 XML 应答(您也可以通过 __getLastRequest()) 将其用于请求调试。

                      一些额外的观察/问题:

                      • 根据发布的 WSDL,“CanLoadProductRequest”有第五个参数“esn”,您没有在函数调用中提供。
                      • 你为什么使用$client-&gt;__soapCall("CanLoadProduct", $params)而不是$client-&gt;CanLoadProduct($username, $password, etc.)? (第一个版本是一个较低级别的变体,旨在用于 non_WSDL 场景。第二个版本可能会给您更详细的错误/异常)
                      • 您能否通过其他方式测试对 CanLoadProductRequest 的 SOAP 调用?错误可能在服务器端,试图返回不符合 WSDL 定义的结果类型。

                      【讨论】:

                      • “esn”是可选的,这种数据 user/pass/prod/mdn/esn 模式对于我使用的其他 8 个调用中的大多数都是标准的,除了这个之外似乎没有一个失败.我已经尝试过 $client->CanLoadProduct($params),但它导致:PHP 中的数组到字符串转换通知
                      • Oups - 抱歉,如果您使用 $client->CanLoadProduct() 表示法,您不会传递参数数组,而是像使用标准函数调用一样传递单个参数(例如 $client ->CanLoadProduct($username, $password, etc.)) )
                      • 要尝试的另一件事是在调用之前将参数显式转换为字符串(例如,productid 可能在此处作为 int 传递)
                      • 根据来自 cmets 的新假设编辑答案。
                      • 我已将此标记为答案,因为它帮助我检查了所有可能的问题。我得出的结论是 WSDL 导致了错误,因为它是一个如此简单的 SOAP 调用,我最终没有使用它,因为它是一个“检查”调用,如果它没有通过,post check 函数将返回一个失败消息也可以作为支票使用。我向 API 的设计者提出了这个问题。感谢大家的帮助!
                      猜你喜欢
                      • 2012-08-05
                      • 1970-01-01
                      • 1970-01-01
                      • 1970-01-01
                      • 1970-01-01
                      • 1970-01-01
                      • 1970-01-01
                      • 1970-01-01
                      相关资源
                      最近更新 更多