【问题标题】:SOAP-ERROR: Parsing WSDL: Couldn't load from - but works on WAMPSOAP-ERROR:解析 WSDL:无法加载 - 但适用于 WAMP
【发布时间】:2014-02-18 17:28:50
【问题描述】:

这在我的 WAMP 服务器上可以正常工作,但在 linux 主服务器上不起作用!?

try{
    $client = new SoapClient('http://ec.europa.eu/taxation_customs/vies/checkVatService.wsdl', ['trace' => true]);
    $result = $client->checkVat([
        'countryCode' => 'DK',
        'vatNumber' => '47458714'
    ]);
    print_r($result);
}
catch(Exception $e){
    echo $e->getMessage();
}

我在这里错过了什么?! :(

SOAP 已启用

错误

SOAP-ERROR: Parsing WSDL: Couldn't load from 'http://ec.europa.eu/taxation_customs/vies/checkVatService.wsdl' : failed to load external entity "http://ec.europa.eu/taxation_customs/vies/checkVatService.wsdl"/taxation_customs/vies/checkVatService.wsdl"

从 PHP 调用 URL

从 PHP 调用 URL 返回错误

$wsdl = file_get_contents('http://ec.europa.eu/taxation_customs/vies/checkVatService.wsdl');
echo $wsdl;

错误

Warning:  file_get_contents(http://ec.europa.eu/taxation_customs/vies/checkVatService.wsdl): failed to open stream: HTTP request failed! HTTP/1.0 503 Service Unavailable

从命令行调用 URL

从 linux 命令行调用 URL HTTP 200 会返回一个 XML 响应

curl http://ec.europa.eu/taxation_customs/vies/checkVatService.wsdl

【问题讨论】:

  • 如果你在 Linux 服务器的 shell 上运行 curl http://ec.europa.eu/taxation_customs/vies/checkVatService.wsdl 会说什么?
  • HTTP 200 和 XML 是响应
  • 听起来可能是字符编码问题。 WDSL 是否以 SOAP 客户端期望的字符集编码?

标签: php soap


【解决方案1】:

对于某些版本的 php,SoapClient 不发送 http 用户代理信息。与本地 WAMP 相比,您在服务器上有哪些 php 版本?

尝试使用上下文流显式设置用户代理,如下所示:

try {
    $opts = array(
        'http' => array(
            'user_agent' => 'PHPSoapClient'
        )
    );
    $context = stream_context_create($opts);

    $wsdlUrl = 'http://ec.europa.eu/taxation_customs/vies/checkVatService.wsdl';
    $soapClientOptions = array(
        'stream_context' => $context,
        'cache_wsdl' => WSDL_CACHE_NONE
    );

    $client = new SoapClient($wsdlUrl, $soapClientOptions);

    $checkVatParameters = array(
        'countryCode' => 'DK',
        'vatNumber' => '47458714'
    );

    $result = $client->checkVat($checkVatParameters);
    print_r($result);
}
catch(Exception $e) {
    echo $e->getMessage();
}

编辑

实际上您使用的网络服务似乎存在一些问题。 IPv6 上的 HTTP 和缺少 HTTP 用户代理字符串的组合似乎给 Web 服务带来了问题。

要验证这一点,请在您的 linux 主机上尝试以下操作:

curl  -A ''  -6 http://ec.europa.eu/taxation_customs/vies/checkVatService.wsdl

此 IPv6 请求失败。

curl  -A 'cURL User Agent'  -6 http://ec.europa.eu/taxation_customs/vies/checkVatService.wsdl

此 IPv6 请求成功。

curl  -A ''  -4 http://ec.europa.eu/taxation_customs/vies/checkVatService.wsdl
curl  -A 'cURL User Agent'  -4 http://ec.europa.eu/taxation_customs/vies/checkVatService.wsdl

这两个 IPv4 请求都成功。

有趣的案例 :) 我猜您的 linux 主机将 ec.europa.eu 解析为其 IPv6 地址,并且您的 SoapClient 版本默认没有添加用户代理字符串。

【讨论】:

  • 您说 IPv6 请求失败,但没有具体说明如何。如果它以 503 状态码失败,我将删除我的答案。我在哪里,上面写着Failed to connect to 2001:bc8:3408:200::2: Network is unreachable
  • 没错,请求失败并返回HTTP/1.0 503 Service Unavailable。 503 响应的正文是Erreur 503 Erreur proxy ipv6
  • 报告的 SoapClient 用户代理错误bugs.php.net/bug.php?id=60887的链接
  • 好的,所以我在回答中没有想到的是尝试 IPv6。你赢了。我要删除我的答案。
  • https url 的流上下文:stackoverflow.com/a/28701786/2042775
【解决方案2】:

安全问题:此答案禁用安全功能,不应在生产中使用!

试试这个。希望对你有帮助

$options = [
    'cache_wsdl'     => WSDL_CACHE_NONE,
    'trace'          => 1,
    'stream_context' => stream_context_create(
        [
            'ssl' => [
                'verify_peer'       => false,
                'verify_peer_name'  => false,
                'allow_self_signed' => true
            ]
        ]
    )
];

$client = new SoapClient($url, $options);

【讨论】:

    【解决方案3】:

    这个问题可能是由于 libxml 实体加载器被禁用造成的。

    在实例化SoapClient 之前尝试运行libxml_disable_entity_loader(false);

    【讨论】:

    【解决方案4】:

    这可能对某人有帮助,尽管这个问题没有确切的答案。

    我的soap url有一个非标准端口(例如9087),防火墙阻止了该请求,我每次都收到这个错误:

    错误 - 2017-12-19 20:44:11 --> 致命错误 - SOAP-ERROR:解析 WSDL:无法从 'http://soalurl.test:9087/orawsv?wsdl' 加载: 未能加载外部实体“http://soalurl.test:9087/orawsv?wsdl

    我在防火墙中允许端口并解决了错误!

    【讨论】:

    • 也节省了我的时间,完全相同的问题
    【解决方案5】:

    尝试改变

    $client = new SoapClient('http://ec.europa.eu/taxation_customs/vies/checkVatService.wsdl', ['trace' => true]);
    

    $client = new SoapClient('http://ec.europa.eu/taxation_customs/vies/checkVatService.wsdl', ['trace' => true, 'cache_wsdl' => WSDL_CACHE_MEMORY]);
    

    另外(无论是否有效),请检查以确保您的网络服务器可写入 /tmp 并且它未满。

    【讨论】:

    • @clarkk 小改动(添加了单引号),抱歉。另外,/tmp 好吗?另外,phpinfo() 告诉你什么?
    • 另一个想法:服务器可以重定向到 https 吗?您是否根据请求运行了 wireshark 或 Fiddler?
    • 我看到了带有单引号的错字 :) 并且没有重定向.. 已在 www.web-sniffer.net 尝试过请求
    • 正如我在问题中所写的,我可以在命令行中使用 curl 调用 URL。这一定是 PHP 中的错误配置...在使用 debian 6 和 php5.3 的旧服务器上它起作用了.. 没有用 php.ini 胡闹,而且它几乎是开箱即用的
    【解决方案6】:

    尝试在你的 php.ini 中启用 openssl 扩展,如果它被禁用的话。 这样我就可以在不需要任何额外参数的情况下访问 Web 服务,即,

    $client = new SoapClient(url);
    

    【讨论】:

      【解决方案7】:

      以上方法都不适合我,所以经过大量研究后,我最终预先下载了 wsdl 文件,将其保存在本地,并将该文件作为第一个参数传递给 SoapClient。

      值得一提的是 file_get_contents($serviceUrl) 为我返回了空响应,而 url 在我的浏览器中打开得很好。这可能就是 SoapClient 也无法加载 wsdl 文档的原因。所以我最终用 php curl 库下载了它。这是一个例子

      $ch = curl_init();
      curl_setopt($ch, CURLOPT_URL, $serviceUrl);
      curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
      $wsdl = curl_exec($ch);
      curl_close($ch);
      
      $wsdlFile = '/tmp/service.wsdl';
      file_put_contents($wsdlFile, $wsdl);
      
      $client = new SoapClient($wsdlFile);
      

      您当然可以为 wsdl 文件实施自己的缓存策略,因此不会在每次请求时都下载它。

      【讨论】:

        【解决方案8】:

        503 表示功能正在运行,并且您从远程服务器获得拒绝您的响应。如果您曾经尝试对谷歌结果进行 cURL 搜索,同样的事情也会发生,因为他们可以检测到 file_get_contents 和 cURL 使用的用户代理,从而阻止这些用户代理。您访问的服务器也有可能将其 IP 地址列入黑名单。

        这些命令无法像远程情况下的浏览器一样工作的主要三个常见原因。

        1) 默认的 USER-AGENT 已被阻止。 2)您的服务器的IP块已被阻止。 3) 远程主机有代理检测。

        【讨论】:

          【解决方案9】:

          经过数小时的分析,阅读大量日志和互联网,终于找到了问题。

          如果您使用 docker 和 php 7.4(我的情况),您可能会收到错误,因为 OpenSSL 中的默认安全级别对于 wsdl 证书来说太高了。 即使您在 SoapClient 选项中禁用验证并允许自签名。

          你需要在/etc/ssl/openssl.cnf 中从DEFAULT@SECLEVEL=2 到更低的seclevel 到

          DEFAULT@SECLEVEL=1
          

          或者只是添加到 Dockerfile 中

          RUN sed -i "s|DEFAULT@SECLEVEL=2|DEFAULT@SECLEVEL=1|g" /etc/ssl/openssl.cnf
          

          来源:https://github.com/dotnet/runtime/issues/30667#issuecomment-566482876


          您可以通过在容器上运行来验证它

          curl -A 'cURL User Agent' -4 https://ewus.nfz.gov.pl/ws-broker-server-ewus/services/Auth?wsdl
          

          在那次更改之前我遇到了错误:

          SSL routines:tls_process_ske_dhe:dh key too small
          

          【讨论】:

            【解决方案10】:

            我使用 AdWords API,但有时我也会遇到同样的问题。 我的解决方案是添加 ini_set('default_socket_timeout', 900); 在文件上 供应商\googleads\googleads-php-lib\src\Google\AdsApi\AdsSoapClient.php 第 65 行

            并且在 供应商\googleads-php-lib\src\Google\AdsApi\Adwords\Reporting\v201702\ReportDownloader.php 第 126 行 ini_set('default_socket_timeout', 900); $requestOptions['stream_context']['http']['timeout'] = "900";

            Google 包覆盖默认的 php.ini 参数。

            有时,页面可以连接到 'https://adwords.google.com/ap i/adwords/mcm/v201702/ManagedCustomerService?wsdl 有时没有。 如果页面连接一次,WSDL缓存会包含相同的页面,程序会ok,直到代码刷新缓存...

            【讨论】:

              【解决方案11】:

              在最后添加?wsdl并调用方法:

              $client->__setLocation('url?wsdl'); 
              

              对我有帮助。

              【讨论】:

                【解决方案12】:

                我可能已经阅读了这两天的所有问题。没有一个答案对我有用。

                就我而言,我缺少 PHP 的 cURL 模块。

                请注意,仅仅因为您可以在终端上使用 cURL,并不意味着您拥有 PHP cURL 模块并且它处于活动状态。 没有显示错误。甚至在/var/log/apache2/error.log

                如何安装模块: (替换版本号)

                sudo apt install php7.2-curl
                sudo service apache2 reload
                

                【讨论】:

                  【解决方案13】:

                  我遇到了同样的问题

                  从本地机器一切正常(wamp + php5.5.38 或 vagrant + php 7.4),但从 prod linux 服务器我有错误

                  SOAP-ERROR: Parsing WSDL: Couldn't load from 'http://ec.europa.eu/taxation_customs/vies/checkVatService.wsdl' : failed to load external entity "http://ec.europa.eu/taxation_customs/vies/checkVatService.wsdl"
                  

                  从 chrome 中的重定向路径插件我发现永久重定向到 https,但将 url 更改为 https 没有帮助。

                  Status Code    URL    IP    Page Type    Redirect Type    Redirect URL    
                  

                  301 http://ec.europa.eu/taxation_customs/vies/checkVatService.wsdl 147.67.210.30 server_redirect 永久https://ec.europa.eu/taxation_customs/vies/checkVatService.wsdl 200 https://ec.europa.eu/taxation_customs/vies/checkVatService.wsdl 147.67.210.30 正常 无 无

                  在尝试了几次不同的代码解决方案后,我的服务器提供商得到了帮助。他发现了 ipv6 的 IP 转发问题。

                  http://ec.europa.eu/
                  
                  Pinging ec.europa.eu [147.67.34.30] with 32 bytes of data:
                  Request timed out.
                  Request timed out.
                  Request timed out.
                  

                  建议是用户 stream_context_create 使用套接字并绑定到 0:0。这迫使 ipv4

                  // https://www.php.net/manual/en/context.socket.php
                  
                  $streamContextOptions = [
                    'socket' => [
                      'bindto' => '0:0'
                    ],
                  ];
                  
                  $streamContext = stream_context_create($streamContextOptions);
                  
                  $soapOptions = [
                    'stream_context' => $streamContext
                  ];
                  
                  $service = new SoapClient('https://ec.europa.eu/taxation_customs/vies/checkVatService.wsdl', $soapOptions);
                  

                  【讨论】:

                    【解决方案14】:

                    我有类似的错误,因为我不小心删除了属性 [ServiceContract] 来自我的合同,但服务主机仍然成功打开。失误发生

                    【讨论】:

                      【解决方案15】:

                      我是这样解决的:

                      您提供“主机”的每家公司都有一个防火墙

                      当您的源 IP 未在该防火墙 中定义时,会发生此错误。 联系服务器管理员添加IP

                      或者目标IP必须在服务器防火墙白名单中定义。

                      【讨论】:

                        【解决方案16】:

                        可以尝试查看端点是否也支持https

                        【讨论】:

                          【解决方案17】:

                          以下解决方案对我有用。

                          1- 使用 apache 在 ubuntu 中转到 php.ini/etc/php/7.4/apache2 (注意:你应该用你的php版本替换7.4

                          2- 从这一行中删除 ; ;extension=openssl 以取消注释。

                          3- 重启你的网络服务器sudo service apache2 restart

                          【讨论】:

                            猜你喜欢
                            • 1970-01-01
                            • 1970-01-01
                            • 1970-01-01
                            • 1970-01-01
                            • 2011-02-27
                            • 1970-01-01
                            • 2018-08-27
                            • 1970-01-01
                            • 1970-01-01
                            相关资源
                            最近更新 更多