【问题标题】:How to create soap request and send XML to the WSDL then receive back the response in XML?如何创建soap请求并将XML发送到WSDL,然后以XML接收响应?
【发布时间】:2020-01-14 09:06:34
【问题描述】:

我正在通过 API 创建集成。基本上我要做的是创建soap请求并将XML发送到WSDL,然后也以XML形式接收响应,以便稍后解析它。

对我来说问题是......如何开始,因为我不知道肥皂请求规则,而且我很难找到对我的情况有帮助的好的知识资源。如果你有,请将链接粘贴给我,以便我阅读它(已经检查过 PHP 手册 SoapClient,但它现在对我来说很神奇)。

我现在通过 SoapClient 类解析 URL 到 WSDL 创建一个对象:

$soap = new SoapClient('https://wasstt.infomonitor.pl/bigApi/v1/ReportOrderService/WEB-INF/wsdl/wsBigApi1v1.wsdl');

我还使用了 __getFunctions() 方法,所以我可以看到里面的函数:

print_r($soap->__getFunctions()); 

在上面代码的结果中,我得到了一个带有函数的数组,它的外观如下:

(

[0] => ResponseMessage addOrder(RequestMessage $addOrderRequest)
[1] => ResponseMessage getOrderList(RequestMessage $getOrderListRequest)
[2] => ResponseMessage getOrderStatus(RequestMessage $getOrderStatusRequest)
[3] => ResponseMessage getReport(RequestMessage $getReportRequest)
[4] => ResponseMessage getStatistic(RequestMessage $getStatisticRequest)
[5] => ResponseMessage checkAppStatus(RequestMessage $checkAppStatusRequest)
[6] => ResponseMessage updateMonitoring(RequestMessage $updateMonitoringRequest)
[7] => ResponseMessage removeTracedEvents(RequestMessage $removeTracedEventsRequest)
[8] => ResponseMessage getMonitoredEntities(RequestMessage $getMonitoredEntitiesRequest)
[9] => ResponseMessage getTracedEvents(RequestMessage $getTracedEventsRequest)
[10] => ResponseMessage whoMonitorsMe(RequestMessage $whoMonitorsMeRequest)
[11] => ResponseMessage updateEconomicInformation(RequestMessage $updateEconomicInformationRequest)
[12] => ResponseMessage updateLiability(RequestMessage $updateLiabilityRequest)

)

在这一刻,隧道里似乎有一盏灯,因为有一个我应该调用的函数 getReport,但问题是如何?我知道有一个__soapCall(php手册):

public SoapClient::__soapCall ( string $function_name , array $arguments [, array $options [, mixed $input_headers [, array &$output_headers ]]] ) : mixed

但我不知道下一步应该做什么以及如何做。

@已编辑

我尝试过不同的方式并做到了:

$report = $soap->getReport($xml); //getReport is the valid function

我收到了下面的消息:

cvc-complex-type.2.4.a: Invalid content was found starting with element 'testDataMarker'. One of '{requestId}' is expected.

【问题讨论】:

  • @dharman 标题已更改
  • 如果您按照the manual 中的示例操作__soapCall() 会发生什么?那里的 cmets 中通常也有更多信息。请向我们展示您的尝试以及会发生什么。
  • @MagnusEriksson 我尝试了不同的方式并编辑了我的主题帖子

标签: php xml soap


【解决方案1】:

如果您遵循 Web 标准,使用 PHP 的 Soap 请求实际上非常简单。 PHP SoapClient 类旨在为您完成整个 xml 工作。如果您只使用从 WSDL 文件派生的对象,那将变得非常容易。

你是在正确的方式。第一步应该是从 WSDL 文件中确定函数和数据类型。您已经使用 $client->__getFunctions() 和 $client->__getTypes() 函数完成了这项工作。

ResponseMessage getReport(RequestMessage $getReportRequest)

这提供了以下信息。如果要调用web服务的getReport函数,必须在请求中使用RequestMessage对象,并接收ResponseMessage对象作为响应。那么我们从哪里获得这些方法呢?这些信息写在链接的XSD file 中,或者您也可以使用$client->__getTypes() 函数。这将为我们提供以下信息。

struct ResponseMessage {
    messageId responseId;
    dateTime responseDateTime;
    messageId requestId;
    dateTime requestDateTime;
    string user;
    protocolEnum protocol;
    string customProtocol;
    string data;
}

RequestMessage {
    messageId requestId;
    dateTime requestDateTime;
    protocolEnum protocol;
    string customProtocol;
    boolean testDataMarker;
    string data;
}

我们可以将一个结构体翻译成一个 PHP 类。这个类就是所谓的值对象。

class RequestMessage
{
    protected $requestId;

    protected $requestDateTime;

    protected $protocol;

    protected $customProtocol;

    protected $testDataMarker;

    protected $data;

    public function getRequestId(): ?string
    {
        return $this->requestId;
    }

    public function setRequestId(?string $requestId): self
    {
        $this->requestId = $requestId;
        return $this;
    }

    public function getRequestDateTime(): ?string
    {
        return $this->requestDateTime;
    }

    public function setRequestDateTime(?string $requestDateTime): self
    {
        $this->requestDateTime = $requestDateTime;
        return $this;
    }

    public function getProtocol(): ?string
    {
        return $this->protocol;
    }

    public function setProtocol(?string $protocol): self
    {
        $this->protocol = $protocol;
        return $this;
    }

    public function getCustomProtocol(): ?string
    {  
        return $this->customProtocol;
    }

    public function setCustomProtocol(?string $customProtocol): self
    {
        $this->customProtocol = $customProtocol;
        return $this;
    }

    public function getTestDataMarker(): ?bool
    {
        return $this->testDataMarker;
    }

    public function setTestDataMarker(?bool $testDataMarker): self
    {
        $this->testDataMarker = $testDataMarker;
        return $this;
    }

    public function getData(): ?string
    {
        return $this->data;
    }

    public function setData(?string $data): self
    {
        $this->data = $data;
        return $this;
    }
}

class Credentials 
{
    protected $user;

    protected $password;

    public function getUser(): ?string
    {
        return $this->user;
    }

    public function setUser(?string $user): self
    {
        $this->user = $user;
        return $this;
    }

    public function getPassword(): ?string
    {
        return $this->password;
    }

    public function setPassword(?string $password): self
    {
        $this->password = $password;
        return $this;
    }
}

这是一个简单的 PHP 值对象,带有用于类属性的 getter 和 setter。这些属性与结构信息中所述的完全相同。您可以对 $client->__getTypes() 函数返回的所有结构执行此操作。如果所有类型都映射到 PHP 值对象类,soap 客户端甚至会在映射的 php 类中解析响应。如果没有到响应类型的映射,soap 客户端会将 xml 响应解析为stdClass PHP 对象。

对于getReport 示例,我们需要RequestMessage 和Credentials 值对象。

下一步是使用正确的选项参数初始化SoapClient 类。初始化后,我们需要设置凭证标头,然后为我们的请求设置数据。

try {
    $client = new SoapClient(
        'https://wasstt.infomonitor.pl/bigApi/v1/ReportOrderService/WEB-INF/wsdl/wsBigApi1v1.wsdl',
        [
            'trace' => true,
            'exception' => true,
            'compression' => SOAP_COMPRESSION_ACCEPT | SOAP_COMPRESSION_GZIP,
            'soap_version' => SOAP_1_1,
            'classmap' => [
                'Credentials' => Credentials::class,
                'RequestMessage' => RequestMessage::class,
            ],
        ]
    );

    // set the credentials header
    $credentials = (new Credentials())
        ->setUser('user')
        ->setPassword('password');

    $header = new SoapHeader('http://api.big.pl/bigApi/v1/types', 'credentials', $credentials, false);
    $client->__setSoapHeaders([ $header ]);

    // set the request data
    $requestMessage = (new RequestMessage())
        ->setRequestId(1)
        ->setRequestDateTime('2020-01-15T15:00:00')
        ->setProtocol('bimo v1')
        ->setTestDataMarker(true)
        ->setData('test');

    $result = $client->getReport($requestMessage);
    var_dump($result);
} catch (SoapFault $fault) {
    var_dump($fault, $client->__getLastRequest(), __LINE__);
}

如您所见,SoapClient 类的初始化包含在 try / catch 块中。这使您能够捕获错误。 trace 选项使您能够获取发送的请求和接收的响应 xml。 classmap 选项包含我们从$client->__getTypes() 函数获得的xsd 类型。 classmap 使soap 客户端能够将类型映射到您的值对象类。

我们知道,getReport webservice 函数需要一个RequestMessage 对象作为参数,我们使用我们的RequestObject 值对象类和我们要在请求中提交的所有值。

发送的xml请求如下:

<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope
    xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
    xmlns:ns1="http://api.big.pl/bigApi/v1/types">
    <SOAP-ENV:Header>
        <ns1:credentials>
            <user>user</user>
            <password>password</password>
        </ns1:credentials>
    </SOAP-ENV:Header>
    <SOAP-ENV:Body>
        <ns1:getReportRequest>
            <requestId>1</requestId>
            <requestDateTime>2020-01-15T15:00:00</requestDateTime>
            <protocol>bimo v1</protocol>
            <testDataMarker>true</testDataMarker>
            <data>test</data>
        </ns1:getReportRequest>
    </SOAP-ENV:Body>
</SOAP-ENV:Envelope>

此 xml 由 SoapClient 类自动生成。最终,此请求会导致身份验证错误,因为我不知道您的凭据。但是现在你知道了,如何在不编写任何 xml 的情况下使用 php 原生 PHP 类发送和接收数据。

希望这对您有所帮助。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-03-11
    • 2011-06-07
    • 1970-01-01
    • 1970-01-01
    • 2012-07-31
    • 1970-01-01
    • 2017-01-17
    相关资源
    最近更新 更多