【问题标题】:PHP - Responding to incoming API call without returningPHP - 响应传入的 API 调用而不返回
【发布时间】:2020-03-07 07:40:53
【问题描述】:

我正在尝试找出最好的方法,将对传入 API POST 的响应发送到我们的系统,而不返回。

我们从另一个服务接收 XML 帖子,并使用它,然后我们对它们的响应也是 XML 格式的。我们目前正在做的是消化传入的帖子,在我们这边做一些事情,然后用 XML 做一个 php 返回。

我想改变这一点,以便我们可以用 XML 响应他们的调用,但在事后进行一些处理,而不进行某种类型的 exec/background 调用。

在 PHP 中发送响应而不返回的最佳方式是什么?如果我们执行“回显”,是否会关闭连接并允许我们在之后处理更多内容而无需其他服务器“等待”?

【问题讨论】:

    标签: php api integration webhooks


    【解决方案1】:

    调用 PHP 的 echo 不会关闭连接,事实上你可以在你的 PHP 脚本中多次调用 echo 并且输出将被添加到响应中。只有在

    1. 脚本结束
    2. 调用exit() 或别名die()
    3. 发生致命/解析错误或未捕获的异常或您的服务器内存不足
    4. 超过了您可以在 php.ini 中设置的最大脚本执行时间

    通常,调用客户端代码也会有某种超时,因此如果您的“消化”代码可能需要更长的时间,并且您想要注意这一点以及列表中的第 4 点,您可以存储请求数据供以后处理,例如在数据库中或在文件中序列化。成功存储数据后,您基本上有两个选择:

    选项 1:生成一个后台 PHP 进程

    要生成一个能够在调用脚本的生命周期中存活的后台 PHP 进程,请使用 execnohup。基本用法可能如下所示:

    exec('RESOURCE_ID=123 nohup /path/to/your/php/executable your_script.php > /dev/null');
    

    在命令的第一段RESOURCE_ID=123 中,您可以将先前存储的请求数据的唯一标识符(可能是数据库条目ID 或存储文件名)传递给后台脚本。在后台脚本中使用getenv('RESOURCE_ID') 来检索变量。

    [EDIT] > /dev/null 用于输出重定向对于在后台运行进程至关重要,否则父脚本将等待后台进程的输出。我还建议将输出和错误输出写入&> my_script.out 之类的实际文件中,这将具有相同的效果。您也可以通过在命令后附加& echo $! 来获取后台进程的进程ID,然后exec() 将返回它。

    启动后台脚本后,您可以发送“OK”响应并退出父脚本。

    选项 2:按 Jim Panse 的建议进行处理的 Cronjob

    您的系统变得越复杂,您可能需要更多地控制“消化”代码的执行。也许您想平衡服务器负载峰值,或者重新启动失败的任务,或者限制对 API 的恶意使用。如果您需要这种控制,最好使用此选项。

    【讨论】:

    • 我希望情况并非如此,但感谢您提供的信息。
    • 当您在代码中连接固定进程调用时,您通常无法运行它们。意味着:启动你的主进程隐式结束于启动你的后台进程。由于来自另一个 php 进程的进一步进程调用通常与主进程的每次调试分离,因此它们更难控制,因此更难调试。另一方面,可以轻松停止调度程序并手动运行 php 代码。
    • @Jim Panse,我大体上同意,并且必须承认我不知道它如何影响例如我不使用的 Xdebug。但我相信选项 1 有一个用例。有时等待长达 1 分钟以等待下一个 cronjob 运行以及任何先前排队的任务完成。
    • @Benni 确实有有效的用例,尤其是在您不需要运行复杂系统的情况下。与生活中的任何地方一样,这始终是一种权衡,取决于具体情况。为了解决 1 分钟的差距,您可以引入某种工作进程,该进程恰好运行一分钟并寻找更改。正如我所说,如果你有一个简单的情况,你不需要这一切。但如果系统变得更复杂,您可能会考虑更强大的解决方案。
    【解决方案2】:

    由于我猜您希望系统间通信同步进行,因此您可以考虑多种因素。

    即使请求很耗时,您通常仍希望得到快速响应。 为了满足这一点,您不能立即处理请求。

    所以,只需保存请求并稍后处理它(给客户端一个 202 响应)。队列之类的系统非常流行,可以节省耗时的作业以供以后运行。然后另一个时间控制脚本(cronjob)可以进行轮询并处理堆叠的消息/数据。

    如果您也想将结果提供给客户端,请在初始的 rest 调用中返回一个唯一的资源 id,并使用该参数作为输入来实现另一个资源。如果您的系统完成处理,结果将出现在那里。

    从另一个 php 脚本中生成一个进程并不是很方便,因为它很难调试并且容易出错。

    我个人不会采用这种解决方案。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-09-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-04-14
      • 1970-01-01
      • 2019-11-12
      • 2020-10-27
      相关资源
      最近更新 更多