日期:2014-04-07  浏览次数:20526 次

处理 SOAP 错误

  如果运行客户机时出现错误怎么办?与其他语言(如 Java)一样,PHP 5 新增加了一种异常机制。ext/soap 使用这种新的机制,以 SoapFault 对象的形式返回错误。比方说,可以用下面这种形式将代码包装起来:

try {
... some SOAP operation
} catch (SoapFault $soapFault) {
echo $soapFault;
}
  注意,与 Java 有所不同,PHP 语言的 try - catch 块不能包含 finally 子句。

  SoapFault 可以在本地生成。比方说,假设输错了 getForecast 的 startDate 参数。客户机的输出就会变成:

SoapFault exception: [SOAP-ENV:Client]
SOAP-ERROR: Encoding: object hasn't 'startDate' property in WeatherClientEJB.php:32
Stack trace: #0 WeatherClientEJB.php(32): SoapClient->getForecast('getForecast', Array)
#1 WeatherClientEJB.php(73): displayForecast(Array)
#2 {main}
  注意,其中没有 trace 输出,因为并没有发送请求。SOAP_ENV:Client 是 SOAP 规范中为 Faulty body 元素 Faultcode 字段定义的值之一。

  这个 SoapFault 是在 ext/soap 内部发现错误时生成的,它没有发送 SOAP 消息。但是 SoapFaults 也可以报告服务器上发现的错误。比如,假设修改代码,将 startDate 参数的值设成“badDateString”。这是一个非法的 ISO 8601 字符串,但是 ext/soap 没有检查提供的格式,仅仅把消息发送到服务器,而服务器拒绝该请求:

Request :
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:ns1="http://session.itso">
<SOAP-ENV:Body>
<ns1:getForecast>
<ns1:startDate>badDateString</ns1:startDate>
<ns1:days>2</ns1:days>
</ns1:getForecast>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>

Response :
<?xml version="1.0" encoding="UTF-8"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<soapenv:Body>
<Fault xmlns="http://schemas.xmlsoap.org/soap/envelope/">
<faultcode xmlns="">Server.generalException</faultcode>
<faultstring xmlns="">
<![CDATA[java.lang.NumberFormatException:
WSWS3046E: Error: Invalid date/time: badDateString]]>
</faultstring>
<detail xmlns=""/>
</Fault>
</soapenv:Body>
</soapenv:Envelope>

SoapFault exception: [Server.generalException] java.lang.NumberFormatException:
WSWS3046E: Error: Invalid date/time: badDateString in WeatherClientEJB.php:32
Stack trace: #0 WeatherClientEJB.php(32): SoapClient->getForecast('getForecast', Array)
#1 WeatherClientEJB.php(73): displayForecast(Array)
#2 {main}
  这一次,SOAP 请求传递给了服务器,但是因为日期格式无效而被拒绝。WeatherForecastEJB 实现抛出一个 java.lang.NumberFormatException,该异常在 SOAP 应答中作为 Faulty body 元素返回,然后作为一个 SoapFault 异常报告给客户机。

  保护 Web 服务

  我们考察了三种安全方法,以及如何在 PHP 中使用它们:

  基本 HTTP 身份验证

  如果 HTTP 服务器要求客户机进行身份验证,就会请求用户输入 id 和口令并在应答中增加 Authentication Required HTTP 头文件。在进行后续操作之前,客户机必须响应包含可接受 Authorization HTTP 头文件的请求。

  请求 HTTP 身份验证的通常是 Web 服务器,而不是 Web 服务提供者。Authentication Required HTTP 头文件被传递给浏览器,浏览器弹出对话框请求用户 id 和口令,然后将用户的应答作为 HTTP Authorization 头文件发送给 Web 服务器。在 PHP 脚本中很容易实现这一点,可以使用 header() 函数发送需要的 HTTP 头文件字段。例如:

if (!isset($_SERVER['PHP_AUTH_USER'])) {
header('WWW-Authenticate: Basic realm="Weather"');
header("HTTP/1.0 401 Unauthorized");
}
echo "Welcome " . $_SERVER['PHP_AUTH_USER'];
  PHP 手册中的使用 PHP 进行 HTTP 身份验证 一章详细介绍了这个过程。

  您可能遇到这样一些 Web 服务,这些服务的提供者要求 PHP Web 服务客户机使用 HTTP 进行验证身份。ext/soap 提供了一种简单的发送 HTTP Authorization 请求头文件的方法,使用传递给 SoapClient 构造函数的 options 数组:

$soapClient = new SoapClient("http://localhost:9080/" .
"ItsoWebService2RouterWeb/wsdl/itso/session/WeatherForecastEJB.wsdl",
array('login' => "userid",
'password' => "password"));
  但是,人们认为 HTTP 基本身份验证不是一种安全的用户验证方法(除非结合使用其他外部安全系统,如 SSL),因为用户名和口令是以明文形式在网络上传递的。 HTTP Digest 验证通过加密口令改进了这种方法,但是并不是所有的浏览器都支持这种改进。而且,PHP 的 header() 函数只支持基本身份验证。

  SSL(安全套接字层)

  一种更加安全的协议是 HTTPS(HTTP over SSL),它使用 SSL 加密 HTTP 消息。SSL 在传输层上工作,不了解 HTTP 或 SOAP 协议。因此,它不能只加密消息中的敏感成分,而必须加密整个消息。HTTPS 可以在浏览器与 Web 服务器之间,或者 Web 服务器与 Web 服务提供者之间使用。

  如果编译并启用了 OpenSSL,那么 PHP 还可以支持 HTTPS。如何在 PHP 脚本中使用 SSL,请参阅 PHP