首页 > 解决方案 > 为什么 __soapCall 抛出“Forbidden”而 __doRequest 成功?

问题描述

让我们考虑下面的 SOAP 客户端示例。它基本上扩展了 PHP 原生版本(注意我们处于wsdl模式):

use SoapClient;
use SoapFault;

abstract class AbstractClient extends SoapClient
{
    abstract protected function getHeaders(): array;

    private function call(string $functionName, array $arguments)
    {
        $this->__setSoapHeaders(
            $this->getHeaders()
        );

        try {
            return $this->__soapCall($functionName, [$arguments]);
        } catch (SoapFault $soapFault) {
            // ... 
        }
    }

    public function sendRequest(string $functionName, array $arguments)
    {
        return $this->call($functionName, $arguments);
    }
}

使用请求 SOAP 服务器__soapCall不断抛出SoapFault

faultstring: Forbidden
faultcode: HTTP

我尝试了不同的配置、更改缓存、SOAP 版本、SSL 流上下文等,但仍然无济于事。

现在,想象用 请求同一个端点__doRequest,传递使用先前实现生成的 XML 请求(XML 是从$this->__getLastRequest()catch 部分中转储的),然后它可以工作,我们从服务器获得预期的响应。

从那里,我覆盖了__doRequest客户端(__doRequest由 PHP 在较低级别调用以执行__soapCall)以查看有什么区别:

public function __doRequest($request, $location, $action, $version, $one_way = 0)
{
    // Output $request, $location, $action, $version and $one_way

    parent::__doRequest($request, $location, $action, $version, $one_way);
}

事实证明,唯一的一个是缺少$action空的参数。所以我对其进行了硬编码,但同样无济于事:再次抛出了 Forbidden 异常。

有人知道这里发生了什么吗?

编辑

经过多次测试,我现在可以看出格式化 XML 请求(不是单行,而是它的“美化”版本)确实有效。也许我错过了某种编码/格式化配置,不幸的是 PHP 文档在这个主题上不是很准确......

标签: phpsoap

解决方案


我终于想出了一个肮脏的解决方案。使用以下方法覆盖__doRequest和格式化请求DOMDocument

public function __doRequest($request, $location, $action, $version, $one_way = 0)
{
    $xml = new DOMDocument();
    $xml->preserveWhiteSpace = false;
    $xml->formatOutput = true;
    $xml->loadXML($request);
    $request = $xml->saveXML();

    return parent::__doRequest($request, $location, $action, $version, $one_way);
}

有谁知道如何配置 PHP SOAP 扩展来正确实现这一点?


推荐阅读