Асинхронный сервер PHP SOAP отправляет сообщение подтверждения перед ответом? - PullRequest
0 голосов
/ 09 мая 2018

Я не уверен, как это сделать. В спецификациях службы SOAP, которую я пишу, говорится, что необходимо отправить сообщение подтверждения еще до того, как оно ответит запрошенным ответом на запрос.

Как это делается в PHP? Я не видел примеров того, как это сделать.

Из требований документа:

Одно сообщение-подтверждение отправлено Партнером по интеграции поставщику. за каждый запрос сообщения SubmitInv. Одно подтверждающее сообщение Поставщик также отправляет Партнеру по интеграции от каждого Ответное сообщение RequestInv

Это НЕ стандартный ответ TCP ack. Это пользовательский ответ в формате SOAP, подтверждающий получение запроса. См. Пример ниже.

После опроса продавца:

Они утверждают, что это устаревшая система, и она была написана для обработки в этот поток. В настоящее время они не могут изменить это. Я сказал ему, что в Более 20 лет программирования, я никогда не видел, чтобы любая система SOAP требовала ACK. Он утверждал, что это связано с необходимостью «ждать» ответов. Видимо, они не понимают, как правильно обращаться с лицами без гражданства обработка.

Я уже пытался сделать это, используя функции буферизации вывода PHP, как описано ниже FoxVSky, она не работает в транзакции SOAP. Кроме того, стандартная библиотека SOAP, встроенная в PHP, и библиотека Zend SOAP имеют возможность сделать это.

Пример:

<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" 
               xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
               xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <soap:Body>
    <PAddRs>
      <RqUID>f11958c8-3fde-42ca-bd94-94fdfca316ef</RqUID>
      <PKey>46dba062-2105-4851-831f-a1d364741329</PKey>
      <AppStatus>
        <AppStatusCode>Accept</AppStatusCode>
      </AppStatus>
    </PAddRs>
  </soap:Body>
</soap:Envelope>

Ответы [ 3 ]

0 голосов
/ 21 мая 2018

Если вы пишете сервис SOAP, почему бы просто не использовать SoapServer вместе с методом handle () ? Вам не нужно фактически реализовывать TCP-квитирование (отправка ACK), а что нет. Я почти уверен, что все это обрабатывается для вас в этих классах / методах.

Контекст отсутствует, так что это мое самое обоснованное предположение.

0 голосов
/ 22 мая 2018

Хорошо, я реализовал обмен сообщениями с подтверждением в моем сервисе SOAP, вот как он вызывается с клиента:

<?php
require_once __DIR__ . '/vendor/autoload.php';
$options = array();
$options['cache_wsdl'] = WSDL_CACHE_NONE;
$options['soap_version'] = SOAP_1_2;
$client = new Zend\Soap\Client("http://localhost/soap/server.php?wsdl", $options);

try {
    // Currently loading example request
    $xml = simplexml_load_file('RequestExample.xml');
    $t_xml = new DOMDocument();
    $t_xml->loadXML($xml->asXML());
    $xml = $t_xml->saveXML($t_xml->documentElement);
    $response = $client->ReqInv($xml);
} catch (Exception $e) {
    $response = 'Exception: '. $e. "\n"; 
}
echo $response;    

И мой сервис:

<?php
require_once __DIR__ . '/vendor/autoload.php';
require(__DIR__ . '/PTResp.php');

use Zend\Soap\AutoDiscover;
use Zend\Soap\Server;
use Zend\Soap\Wsdl;

class PT {
    /**
     * function ReqInv
     * Function to return the inventory for the passed request.
     * 
     *  @param string $request 
     *  @return string
     */
    function ReqInv($request) {
        $pt = new PTResp($request);
        return $pt->toString();
    }   
}

if (isset($_GET['wsdl'])) {
    $wsdl = new AutoDiscover();
    $wsdl->setUri('http://localhost/soap/server.php');
    $wsdl->setClass('PT');
    $wsdl->handle();
} else {
    $server = new Zend\Soap\Server('http://localhost/soap/server.php?wsdl');
    $server->setClass('PT');
    $server->setEncoding('ISO-8859-1');
    $server->handle();
}

И мой класс (в PTResp.php):

class PT {

    function __construct($xml) {
        $this->m = new Mustache_Engine;
        $this->xml = @simplexml_load_string($xml);
        $this->xml->registerXPathNamespace(<my namespace info>);
        $this->SendAck();
        $this->BuildResponse();
    } // function __construct

    /*
    * This is the function that is actually called to return the response to the client.
    */
    function toString() {
        $domxml = new DOMDocument('1.0');
        $domxml->preserveWhiteSpace = false;
        $domxml->formatOutput = true;
        $domxml->loadXML($this->response);
        $this->response = $domxml->saveXML($domxml->documentElement);
        return $this->response;
    } // function toString    

    function SendAck() {        
        $this->Status = "Accept";
        $xml_post_string = $this->m->render(
        '<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
            <soap:Body>
                <ProcurementAddRs xmlns=MyNamespaceInfo">
                    <RqUID>{{RqUID}}</RqUID>
                    <PKey>{{PKey}}</PKey>
                    <ApplicationStatus>
                        <ApplicationStatusCode>{{Status}}</ApplicationStatusCode>
                    </ApplicationStatus>
                </ProcurementAddRs>
            </soap:Body>
        </soap:Envelope>', array("RqUID" =>$this->RqUID, "PKey"=>$this->PKey, "Status"=>$this->Status));
        $url = 'http://localhost/soap/gotit.php'; // in this test, it writes the response to a file. I will be sending it to the endpoint from here
        $this->curl_post_async($url, $xml_post_string);
    } // function SendAck

    function curl_post_async($url, $post_string){
        $parts=parse_url($url);

        $fp = fsockopen($parts['host'],
            isset($parts['port'])?$parts['port']:80,
            $errno, $errstr, 30);

        $out = "POST ".$parts['path']." HTTP/1.1\r\n";
        $out.= "Host: ".$parts['host']."\r\n";
        $out.= "Content-Type: text/xml\r\n";
        $out.= "Content-Length: ".strlen($post_string)."\r\n";
        $out.= "Connection: Close\r\n\r\n";
        if (isset($post_string)) $out.= $post_string;
        fwrite($fp, $out);
        fclose($fp);
    } // function curl_post_async  

    function BuildResponse() {
        $this-response = "<XML response that is built goes here>";
    }

}
0 голосов
/ 18 мая 2018

Вы можете использовать Функции управления выводом PHP

Вот мой пример использования

soapserver.php:

<?php

$data = file_get_contents('php://input');
$fp = fopen('data.txt', 'a');
fwrite($fp, json_encode($data));
fwrite($fp, "\n");

class MySoapServer {

    public function addNumbers($num1, $num2) {
        return $num1 + $num2;
    }

}

$options = array('uri' => 'http://test.local/');
$server = new SoapServer(NULL, $options);
$server->setClass('MySoapServer');

ob_end_clean();
header("Connection: close\r\n");
ignore_user_abort(true);
ob_start();
$server->handle();
$soapXml = ob_get_contents();
$size = ob_get_length();
// Flush (send) the output buffer and turn off output buffering
ob_end_clean();
ob_start();
header("Content-Length: $size");
echo $soapXml;
ob_end_flush();
// Unless both are called !
flush();
// Continue do another process after sent message
//example
sleep(10);
fwrite($fp, "Test Writing\n");
fclose($fp);

?>

soapclient.php:

<?php

// client
$options = array(
    'location' => 'http://test.local/stack/soapserver.php',
    'uri' => 'http://test.local/stack/soapserver.php'
);

$client = new SoapClient(NULL, $options);
echo $client->addNumbers(3, 5); //  8

Вы сразу увидите ответ 8 в браузере. Через 10 секунд вы увидите Test Writing в файле data.txt

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...