web-dev-qa-db-ger.com

PHP SoapClient Timeout

Gibt es sowieso für einen SoapClient Request das Timeout und eine Ausnahme auslösen. Ab sofort bekomme ich PHP Server Timeout, in meinem Fall 60 Sekunden. Grundsätzlich möchte ich: Wenn innerhalb eines bestimmten Zeitraums keine Antwort vom Web-Service vorliegt, würde eine Ausnahme ausgelöst und ich könnte sie einfangen. Die 60 Sekunden Warnung ist nicht das, was ich will.

23
Shamim Hafiz

Schaut mal rein

wenn Sie sich wohl fühlen und in Ihrer Umgebung die Klassen erweitern können.

Es erweitert im Wesentlichen die SoapClient-Klasse und ersetzt den HTTP-Transport durch curl, der die Zeitüberschreitungen verarbeiten kann:

class SoapClientTimeout extends SoapClient
{
    private $timeout;

    public function __setTimeout($timeout)
    {
        if (!is_int($timeout) && !is_null($timeout))
        {
            throw new Exception("Invalid timeout value");
        }

        $this->timeout = $timeout;
    }

    public function __doRequest($request, $location, $action, $version, $one_way = FALSE)
    {
        if (!$this->timeout)
        {
            // Call via parent because we require no timeout
            $response = parent::__doRequest($request, $location, $action, $version, $one_way);
        }
        else
        {
            // Call via Curl and use the timeout
            $curl = curl_init($location);

            curl_setopt($curl, CURLOPT_VERBOSE, FALSE);
            curl_setopt($curl, CURLOPT_RETURNTRANSFER, TRUE);
            curl_setopt($curl, CURLOPT_POST, TRUE);
            curl_setopt($curl, CURLOPT_POSTFIELDS, $request);
            curl_setopt($curl, CURLOPT_HEADER, FALSE);
            curl_setopt($curl, CURLOPT_HTTPHEADER, array("Content-Type: text/xml"));
            curl_setopt($curl, CURLOPT_TIMEOUT, $this->timeout);

            $response = curl_exec($curl);

            if (curl_errno($curl))
            {
                throw new Exception(curl_error($curl));
            }

            curl_close($curl);
        }

        // Return?
        if (!$one_way)
        {
            return ($response);
        }
    }
}
17

Während Andrei mit einer anständigen Lösung verbunden ist, hat diese weniger Code, aber sie kommt zu einer guten Lösung:

Beispielcode:

//
// setting a connection timeout (fifteen seconds on the example)
//
$client = new SoapClient($wsdl, array("connection_timeout" => 15));

Und es gibt auch den Stream-Kontext, wenn Sie eine feinere HTTP-Steuerung benötigen. Siehe die stream_context-Option für new SoapClient()Docs . Unter der Oberfläche verwendet SoapClient die HTTP- und SSL-Transporte.

46
Jon L.
ini_set("default_socket_timeout", 15);
$client = new SoapClient($wsdl, array(......));

Die Option connection_timeout definiert ein Timeout in Sekunden für die Verbindung zum SOAP - Dienst. Diese Option definiert kein Timeout für Dienste mit langsamen Antworten. So begrenzen Sie die Wartezeit auf Anrufe um die Einstellung default_socket_timeout zu beenden, ist verfügbar.

31
gdtv

Die akzeptierte Antwort wird alle Funktionen, die SoapClient bietet, unterbinden. Wie das Setzen der korrekten Inhaltsüberschriften, Authentifizierung usw. 

Dies wäre eine bessere Lösung für das Problem

class MySoapClient extends \SoapClient
{
    private $timeout = 10;

    public function __construct($wsdl, array $options)
    {
        // Defines a timeout in seconds for the connection to the SOAP service.
        // This option does not define a timeout for services with slow responses.
        // To limit the time to wait for calls to finish the default_socket_timeout setting is available.
        if (!isset($options['connection_timeout'])) {
            $options['connection_timeout'] = $this->timeout;
        }

        parent::__construct($wsdl, $options);
    }

    public function setTimeout($timeout)
    {
        $this->timeout = $timeout;
    }

    public function __doRequest($request, $location, $action, $version, $one_way = 0)
    {
        $original = ini_get('default_socket_timeout');
        ini_set('default_socket_timeout', $this->timeout);
        $response = parent::__doRequest($request, $location, $action, $version, $one_way);
        ini_set('default_socket_timeout', $original);

        return $response;
    }

}
4
Sander Visser

Sie können dies über den Composer installieren: https://github.com/ideaconnect/idct-soap-client

Es erweitert den Standard-SoapClient und bietet Optionen zum Festlegen der Anzahl von Wiederholungsversuchen, Verbindungs- und Lesezeitlimits.

1

Bei der Arbeit mit SOAPClient verwende ich folgende Logik:

public function executeSoapCall($method, $params)
{
    try {
        $client = $this->tryGetSoapClient();

        $timeout = ini_get('default_socket_timeout');
        ini_set('default_socket_timeout', 60);//set new timeout value - 60 seconds
        $client->__soapCall($method, $params);//execute SOAP call
        ini_set('default_socket_timeout', $timeout);//revert timeout back
    } catch (\Throwable $e) {
        if (isset($timeout)) {
            ini_set('default_socket_timeout', $timeout);//revert timeout back
        }
    }
}
protected function tryGetSoapClient()
{
    $timeout = ini_get('default_socket_timeout');//get timeout (need to be reverted back afterwards)
    ini_set('default_socket_timeout', 10);//set new timeout value - 10 seconds
    try {
        $client = new \SoapClient($this->wsdl, $this->options);//get SOAP client
    } catch (\Throwable $e) {
        ini_set('default_socket_timeout', 10);//revert back in case of exception
        throw $e;
    }
    $this->iniSetTimeout($timeout);//revert back

    return $client;
}

Dies hilft mir, bis zu 10 Sekunden auf den Verbindungsaufbau und 60 Sekunden auf die Anrufausführung zu warten.

0
Dmytro Lukachuk