繁体   English   中英

SoapFault 异常:无法连接到主机

[英]SoapFault exception: Could not connect to host

有时无法调用 Web 服务。

这个问题一直在发生。

可能是什么问题呢?

Error:
    SoapFault exception: [HTTP] Could not connect to host in 
    0 [internal function]: SoapClient->__doRequest('<?xml version="...', http://.', '', 1, 0)

问题解决了 是缓存的问题

ini_set('soap.wsdl_cache_enabled',0);
ini_set('soap.wsdl_cache_ttl',0);

为了完整性,我添加了我的评论,因为此处列出的解决方案对我没有帮助。 在 PHP 5.6 上,SoapClient 第一次调用SoapClient::SoapClient指定的 WSDL URL,在连接到它并接收结果后,它尝试连接到结果中指定的 WSDL:

<soap:address location="http://"/>

如果 WSDL 与您在SoapClient::SoapClient指定的不同并且无法访问(我的情况是使用http://host.local/ 的SoapUI),则调用失败并显示错误Could not connect to host

PHP 5.4 中的行为有所不同,它始终使用SoapClient::SoapClient的 WSDL。

主机已关闭或响应非常慢。 如果响应缓慢,您可以尝试通过connection_timeout选项或通过default_socket_timeout设置增加超时,看看是否可以减少失败。

http://www.php.net/manual/en/soapclient.soapclient.php

http://www.php.net/manual/en/filesystem.configuration.php#ini.default-socket-timeout

您还可以像 zanlok 指出的那样包含错误处理以重试几次。 如果您确实有用户在等待这些 SOAP 调用,那么您需要将它们排队并在后台处理它们,并在它们完成时通知用户。

错误配置的服务将默认命名空间保留在 tempuri.org

这意味着与 wsdl 的连接将工作,但函数调用将失败。

堆栈跟踪:

SoapClient->__doRequest('http://example.com...', ' http://tempuri.org ....', 2, 0)

要修复此问题,您必须使用__setLocation()显式设置位置

$this->soapClient = new \SoapClient(WS_URL);
$this->soapClient->__setLocation(WS_URL);

php.ini 文件中有一个soap 配置部分,它控制wsdl 访问缓存,可能显示为:

[soap] 
; Enables or disables WSDL caching feature. 
soap.wsdl_cache_enabled=1 ; 
Sets the directory name where SOAP extension will put cache files. 
soap.wsdl_cache_dir="/tmp" 
; (time to live) Sets the number of second while cached file will be used ; instead of original one.  
soap.wsdl_cache_ttl=86400

如果启用了 wsdl 文件缓存,则在 php 代码中更改 wsdl URI 时可能会导致此问题。 在本例中,您可以删除/tmp目录下以wsdl-开头的文件。 或者你只是设置soap.wsdl_cache_enabled=0; soap.wsdl_cache_ttl=0; 每次访问该页面时,PHP 都会获取 wsdl 文件。

这对我有用

$opts = array(
  'ssl' => array('verify_peer' => false, 'verify_peer_name' => false)
);

if (!isset($this->soap_client)) {
  $this->soap_client = new SoapClient($this->WSDL, array(
    'soap_version'   => $this->soap_version,
    'location'       => $this->URL,
    'trace'          => 1,
    'exceptions'     => 0,
    'stream_context' => stream_context_create($opts)
  ));

在我们的例子中,这是一个密码协商问题。 我们随机收到此错误。 我们通过强制这样的密码解决了我们的问题:

$soapClient = new SoapClient ('http://example.com/soap.asmx?wsdl',
    array (
        "stream_context" => stream_context_create (
            array (
                'ssl' => array (
                    'ciphers'=>'AES256-SHA'
                )
            )
        )
    )
);

看起来 PHP 并没有在每次服务调用时协商相同的密码。

我自己遇到了这个问题,经过多次挖掘,我最终发现了 ubuntu 的这个错误:

https://bugs.launchpad.net/ubuntu/+source/openssl/+bug/965371

具体来说

https://bugs.launchpad.net/ubuntu/+source/openssl/+bug/965371/comments/62

openssl s_client -connect site.tld:443失败了,但是openssl s_client -tls1 -connect site.tld:443成功了。 在我的特殊情况下,输出的一部分包括New, TLSv1/SSLv3, Cipher is RC4-MD5所以我适当地设置了 php 上下文 ssl/cipher 值。

在我的情况下,它在连接到 wsdl 后工作,使用函数__setLocation()再次定义位置,因为调用失败并出现错误:

无法连接到主机

如果 WSDL 与SoapClient::SoapClient指定的不同,就会发生这种情况。

似乎错误SoapFault exception: Could not connect to host可能是由几种不同的原因引起的。 在我的情况下,它不是由代理、防火墙或 DNS 引起的(我实际上有来自同一台机器的 SOAP 连接,使用nusoap工作,没有任何特殊设置)。

最后我发现它是由我在 SoapClient 构造local_cert选项中引用的无效pem文件引起的。

解决方案:当我从pem文件中删除证书链时,它只包含证书和私钥,SOAP 调用开始通过。

在我的情况下,wsdl 中的服务地址是错误的。

我的 wsdl 网址是。

https://myweb.com:4460/xxx_webservices/services/ABC.ABC?wsdl

但是那个xml结果中的服务地址是。

<soap:address location="http://myweb.com:8080/xxx_webservices/services/ABC.ABC/"/>

我只是将该 xml 保存到本地文件并将服务地址更改为。

<soap:address location="https://myweb.com:4460/xxx_webservices/services/ABC.ABC/"/>

祝你好运。

终于找到原因了,是因为库在你的系统上找不到CA包。 PHP >= v5.6 默认自动设置verify_peer为 true。 但是,并非所有系统在磁盘上都有已知的 CA 包。

您可以尝试以下程序之一:

1.如果您的系统上有CA文件,请将php.ini中的openssl.cafilecurl.cainfo设置为您的CA文件的路径。

2.手动指定你的SSL CA文件位置

curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);  
curl_setopt($cHandler, CURLOPT_CAINFO, $path-of-your-ca-file);

3.禁用verify_peer

curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);

对于那些与我一样在使用 laravel artisan 控制台命令而苦苦挣扎的人,该命令向外部肥皂服务器的相同 wsdl 发出大量请求,然后在一段时间后因Could not connect to host错误而失败。

问题是因为我每次在发出请求之前都在创建新的SoapClient实例。 不要那样做。 创建一次并从同一客户端发出每个请求。

希望能帮助到你。

对我来说,这是一个证书问题。 以下为我工作

$context = stream_context_create([
    'ssl' => [
        // set some SSL/TLS specific options
        'verify_peer' => false,
        'verify_peer_name' => false,
        'allow_self_signed' => true
    ]
]);

$client  = new SoapClient(null, [
    'location' => 'https://...',
    'uri' => '...', 
    'stream_context' => $context
]);

如果您的服务器上有防火墙,请确保打开 SOAP 使用的端口。

就我而言,我必须打开端口 1664。

iptables -t filter -A INPUT -p tcp --dport 1664 -j ACCEPT
iptables -t filter -A OUTPUT -p tcp --dport 1664 -j ACCEPT

如果 ujava 的解决方案不能帮助你,你可以尝试使用 try/catch 来捕捉这个致命的,这对我来说很好。

try{
    $res = $client->__call('LineStopQueryJson',array('Parameters' => $params));
}catch(SoapFault $e){
    print_r($client);
}

对我来说,WCF 服务的 app.config 中的基地址中存在这个问题:当我使用时:

<baseAddresses><add baseAddress="http://127.0.0.1:9022/Service/GatewayService"/> </baseAddresses>

如果使用 .net 连接公共 ip 或域就可以了。

但是当使用 PHP 的 SoapClient 连接到“ http://[online ip]:9022/Service/GatewayService ”时,会抛出异常“Coulod not connect to host”

我已将 baseAddress 更改为 [online ip]:9022,一切正常。

对我来说,这是一个 DNS 问题。 我的 VPS 的域名服务器坏了,所以我通过编辑我的 /etc/resolv.conf 切换到 Google 的: nameserver 8.8.8.8 nameserver 8.8.4.4

此错误的另一个可能原因是当您创建并保持打开的连接过多时。

SoapClient 默认发送 HTTP 标头Connection: Keep-Alive (通过构造函数选项keep_alive )。 但是,如果您为队列中的每个调用创建一个新的 SoapClient 实例,则每次都会创建并保持打开一个新连接。 如果调用执行得足够快,您最终将遇到 1000 个左右的打开连接的限制,这会导致SoapFault: Could not connect to host

因此,请确保您创建了 SoapClient 一次,并将其重用于后续调用。

我有一个糟糕的 php.ini 配置。 验证路径和证书有效性...

[openssl]
openssl.cafile = "C:/good/phpath/ca-bundle.crt"

因为我的新 \\SoapClient($wsdl) 是 https !

只是为了帮助遇到此错误的其他人, <soap:address location="https://some.url"/>的 url 具有无效证书并导致错误。

对我来说,这是httpd服务(Fedora 24)中的一个问题。 一个简单的重启就成功了:

sudo service httpd restart

如果连接是通过 SSL,则可能是服务器而不是客户端的问题(这是我的情况)。

在 PHP 5.6 和 7 以上的版本中,检查服务器证书中使用的 CipherSuite 很重要。 有此版本允许的密码的完整列表以及此 Web 链接中没有的密码的完整列表: https : //wiki.mozilla.org/Security/Server_Side_TLS#Recommended_Ciphersuite

如果使用的密码不被允许(它是一个不推荐使用的算法),SoapClient 会收到“无法连接到主机”并且没有更多关于它的跟踪。

例如,使用的密码可以由 SoapUI 等客户端在“SSL 信息”部分进行检查。

互联网上没有线程论坛对此进行处理。

也检查一下: http : //php.net/manual/en/migration56.openssl.php

在我的情况下,主机需要 TLS 1.2,因此需要使用 crypto_method ssl 参数来强制执行。

$client = new SoapClient($wsdl,
    array(
           'location' => $location,
           'keep_alive' => false,
           "stream_context" => stream_context_create([
                'ssl' => [
                    'crypto_method' =>  STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT,
                ]
            ]),
           'trace' => 1, // used for debug
        )
    );

就我而言,禁用 SELINUX 允许 PHP 调用我的 WebService。 我使用 Apache2 在 FPM 中运行 PHP

SELinux 状态:

# sestatus

禁用 SELinux :

设置强制 0

启用 SELinux :

# setenforce 1

永久禁用:

edit this file /etc/selinux/config

版本检查帮助了我 OpenSSL。 OpenSSL_1_0_1f 不支持 TSLv.1_2 ! github openssl/openssl上检查版本和与 TSLv.1_2 的兼容性。 并使用新的 openssl 重新生成您的证书

openssl pkcs12 -in path.p12 -out newfile.pem

PS我不知道它们是什么,但是这个解决方案真的很有帮助。

这很可能是指连接问题。 可能是您的 Internet 连接已关闭,或者您尝试使用的 Web 服务已关闭。 我建议使用此服务来查看网络服务是否在线: http : //downforeveryoneorjustme.com/

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM