PHP 提前发送 SOAP 响应?

发布于 2024-09-07 07:26:29 字数 1265 浏览 5 评论 0原文

嗯,这是我一直在处理的一个老问题,但仍然没有解决方案,所以尝试一种新方法。

如何尽早发送 SOAP 响应(在脚本执行结束之前)?

这些问题是由于未在 30 秒之前发送 ACK 文件而导致的,因为完成该过程所需的时间比分配的时间更长。

lush() 不起作用,出现此错误:

org.xml.sax.SAXParseException:XML 文档结构必须在同一实体内开始和结束。

没有flush()我得到这个

org.xml.sax.SAXParseException:文件过早结束。

脚本进程可以接管 180 秒才能完成,等待响应的服务器只等待大约 30 秒就超时(这会导致上述错误)。

关于如何解决这个问题有什么想法吗?

以下是一些代码: 这是我接受和发送即将到来的 SOAP 请求的 ACK 文件的方式

$data = 'php://input';
$content = file_get_contents($data);

if($content) {
    respond('true');
} else {
    respond('false');
}

PHP的响应函数

function respond($tf) {
    $ACK = <<<ACK
<?xml version = "1.0" encoding = "utf-8"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <soapenv:Body>
        <notifications xmlns="http://soap.sforce.com/2005/09/outbound">
            <Ack>$tf</Ack>
        </notifications>
    </soapenv:Body>
</soapenv:Envelope>
ACK;

    print trim($ACK); 
}

使用单线程处理方法,并且在线程完成其处理之前不会发回 ACK 文件。有没有什么方法可以在提交 ACK 后关闭套接字并继续处理,这样我就不会在发送服务器上遇到这些超时问题?

Well this is an old issue I've been dealing with and still no solution, so trying a new approach.

How can I send th SOAP response early (Before script execution ends)?

These issues are cause when the ACK file is not sent before 30 seconds as the process takes longer to complete then the allotted time.

flush() not working, get this error:

org.xml.sax.SAXParseException: XML document structures must start and end within the same entity.

without the flush() I get this

org.xml.sax.SAXParseException: Premature end of file.

The script process can takeover 180 seconds to complete and the server waiting for the response only wait for about 30 seconds before timing out (Which cause the above error).

any thoughts as to how I can fix this?

Here is some of the code: This is how I accept and send the ACK file for the imcoming SOAP request

$data = 'php://input';
$content = file_get_contents($data);

if($content) {
    respond('true');
} else {
    respond('false');
}

The respond function

function respond($tf) {
    $ACK = <<<ACK
<?xml version = "1.0" encoding = "utf-8"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <soapenv:Body>
        <notifications xmlns="http://soap.sforce.com/2005/09/outbound">
            <Ack>$tf</Ack>
        </notifications>
    </soapenv:Body>
</soapenv:Envelope>
ACK;

    print trim($ACK); 
}

PHP uses a single thread processing approach and will not send back the ACK file until the thread has completed it's processing. Is there some way to close the socket after the ACK submission and continue the processing so I don't get these timeout issues on the sending server?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

夜夜流光相皎洁 2024-09-14 07:26:29

据我所知,我们无法对 30 秒的限制做任何事情,并且在脚本完成之前输出不会被刷新。你能尝试将你的处理逻辑分成两部分吗?

  1. “监听器”脚本接受消息、记录要完成的作业并立即发送 ACK,然后退出。
  2. 您这边的实际处理可能需要更长的时间。

“要完成的工作”可能是一个新生成的进程(查看 pcntl_fork() 函数,但它们对我来说看起来不太有希望)或某种将数据存储在文件或数据库中并使用另一个脚本定期处理它的方法,例如计划每 5 分钟运行一次?

如果 60 秒能以某种方式拯救您,您可以将出站消息重写为来自 Apex 的标注。基本上,您可以编写自己的 SOAP 信封并将其发送到任何 http 地址。你可以把它放在触发器中。不过,请参阅此处了解此方法的局限性。


其他咆哮:

  1. 我认为你的 ACK 对销售人员来说并不真正“重要”。出站消息只是通知。您的应用程序中的其他地方是否依赖 Ack = true/false?如果不是 - 盲目发送 ack=true & 的侦听器安排工作可能确实是可行的方法;)
  2. 从另一个问题我了解到您基本上只需要在数据库中存储更新即可。您意识到您不应该将 OM 用于审计目的,对吧? (链接,搜索“audit”)。
  3. 让PHP成为主动方不是更简单吗?让它在 Salesforce 中查询 [SELECT Id, Name FROM Account WHERE LastModifiedDate > :上次您查询的时间]?这样您就可以花所有时间来处理结果:)

As far as I know we can't do anything about the 30 second limit and the output won't be flushed before the script finishes. Can you try splitting your processing logic into 2 pieces?

  1. "Listener" script that accepts messages, logs the job to be done and sends ACK instantly, then quits.
  2. Actual processing on your side which might take longer.

The "job to be done" could be a newly spawned process (check out the comments for the pcntl_fork() function but they don't look too promising to me) or some way to store the data in file or database and periodically process it with another script, for example scheduled to run every 5 minutes?

If 60 seconds would somehow save you, you could rewrite your outbound message into a callout from Apex. Basically you then write your own SOAP envelope and send it to any http address. You could put it in a trigger. See here for limitations of this approach though.


Other ranting:

  1. I don't think your ACK really "matters" to salesforce. Outbound messages are just notifications. Do you rely somewhere else in your application on Ack = true/false? If not - listener that blindly sends ack=true & schedules the job might really be the way to go ;)
  2. From the other queston I understood you basically just need to store updates in DB on your side. You realize you shouldn't use OM for audit purposes, right? (Link, search for "audit").
  3. Wouldn't it be simpler to make PHP the active side? make it query Salesforce for [SELECT Id, Name FROM Account WHERE LastModifiedDate > :lastTimeYouQueried]? That way you can take all the time you want to process the results :)
风和你 2024-09-14 07:26:29

a) (可选)您可以使用 set_time_limit() 来增加执行时间的时间限制。

b) 您必须增加 wsdl 客户端对象的时间,例如:

$clientwsdl->setOpt('timeout', 300); // if you are using PEAR:SOAP.

大多数 wsdl 类允许定义超时。

c) 而不是,您无法使用 SOAP 尽早响应,至少不能使用一次调用。考虑到 SOAP 返回 XML,因此部分 XML 通常是无效的(它缺少结束标记)。

d) 或者,您可以使用 SOAP 以外的其他方法,例如读取 url:

$fp=fopen("http://www.mysite.com/url.php","r");

其中 url.php 返回列(或不使用 xml 的某种值:

30|50|70|80|20 
30|50|70|80|20
30|50|70|80|20

a) (optional) you can use set_time_limit() for increase the time limit of the execution time.

b) You must increase the time to the wsdl client object, for example :

$clientwsdl->setOpt('timeout', 300); // if you are using PEAR:SOAP.

Most wsdl class allow to define the timeout.

c) and not, you can't response early using SOAP, not at least using one call. Take in consideration that SOAP return a XML, so a partial XML usually is invalid (it miss the closing tag).

d) Alternate, you can use other method than SOAP, for example reading a url:

$fp=fopen("http://www.mysite.com/url.php","r");

where url.php return the columns (or some kind of value without using xml :

30|50|70|80|20 
30|50|70|80|20
30|50|70|80|20
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文