在PHP中流式传输大型SOAP响应

时间:2011-03-03 18:57:23

标签: php cakephp soap stream

我有一个PHP SOAP Web服务,使用CakePHP,它将可变数量的数据返回给客户端。返回的数据量可能非常少或很大(> 10MB但<100MB)。

我遇到的问题是,响应越大(通常大于5 MB),应用程序内存不足,事情就会崩溃。我尝试改变的第一件事是使用原始SQL查询而不是Cake的数据访问级别。这样,当我从数据库中检索10,000条记录时,Cake不会尝试将其全部保存在内存中。

虽然这是一个糟糕的惯例,但效果确实很好。然而,更大的问题是,一旦我得到结果,它仍会耗尽内存传输响应。我不确定当SoapServer编译响应时是否发生这种情况,或者客户端内存不足以存储响应,或者内存耗尽时只是在屏幕上序列化/呈现数据。

在任何情况下,似乎有一些方法可以将SOAP响应流回客户端,一切都会好得多。无论出现什么问题,数据都可以分解为可管理的块。我不知道如何在PHP中执行此操作,或者甚至可能。

请告知。

1 个答案:

答案 0 :(得分:2)

您应该收到一条错误消息,告诉您内存耗尽的内容。理论上,这应该可以帮助您确定失败的原因。我的猜测是SOAPServer在发送响应之前将响应存储在内存中,可能是因为它使用PHP DomDocument构建XML DOM。 DomDocument(或者可能是SimpleXML)的缺点是必须将整个文档处理到内存中并在将数据序列化为XML之前作为DOM文档有效。

流式传输大量XML数据的更好方法是使用PHP的XMLWriter扩展名。与DOM不同,它不需要将整个文档存储到内存中,它希望您处理文档验证。您可以使用此扩展程序使用XMLWriter::openUri函数直接输出到HTTP响应。这意味着您可以按顺序执行以下操作,并且具有最小的内存开销:

  1. 打开与数据库的连接
  2. 搜索您需要的东西
  3. 使用带有参数php://output的{​​{3}}函数为URI创建XMLWriter的实例。这会将所有内容推送到输出(类似于print / echo)并在内存中存储(几乎)任何内容。确保您已经推出了您需要的任何标题,Cookie等,就像任何其他输出检查一样。
  4. 创建SOAP前导码。
  5. 遍历要在soap响应中返回的项目,将元素添加到输出中。
  6. 创建SOAP postamble
  7. 作为旁注,XMLWriter::openUri的反面是XMLWriter,如果您在读取由于内存限制而无法使用常规方法打开的大型XML文件时会感到很麻烦。