首页 > 解决方案 > JavaScript EventSource 监听 Webhook 推送到 PHP 脚本

问题描述

我一直在寻找和试验,但我似乎无法弄清楚这一点。我将不胜感激。谢谢!

所以我有一个 Shopify 商店,我有一个 Webhook,当我进行销售时触发,这意味着它将销售的 JSON 数据推送到我服务器上的 PHP 脚本。现在,我正在让那个 PHP 脚本将相关数据插入数据库,并将该销售标记为“未读”。然后,我将有一个单独的 HTML/JavaScript 页面,我将单独运行该页面,每隔 10 秒左右轮询服务器以检查未读销售情况。还有一点,但这是一般的想法。它很笨重,我想对其进行现代化改造。

这是我一直在尝试但似乎无法正常工作的方法。

  1. 设置一个监听单独 PHP 脚本的 EventSource 页面。
<html lang="en">
<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Sales Notification!</title>

</head>
<body>
    <div id="widget">
        <div id="notification_box"></div>
    </div>
    <script type="text/javascript">
        if (!!window.EventSource) {
            var source = new EventSource('alert_listener.php');
        } else {
                console.log("Window.EventSource fail!");
        }

        source.addEventListener('message', function(e) {
            console.log(e.data);
        }, false);

        source.addEventListener('open', function(e) {
            // Connection was opened.
        }, false);

        source.addEventListener('error', function(e) {
            if (e.readyState == EventSource.CLOSED) {
                // Connection was closed.
            }
        }, false);
    </script>   
</body>
</html>

当我做一些像这个例子这样简单的事情时,这实际上效果很好。无论如何,这是我的 PHP 代码,用于监听从 Websocket 发送的 JSON(其中一些代码由 Shopify 提供):

<?php
header("Content-Type: text/event-stream");
header("Cache-Control: no-cache");

error_reporting(0);
define('SHOPIFY_APP_SECRET', 'NOT_PUBLIC_HAR_HAR');

function verify_webhook($data, $hmac_header) {
  $calculated_hmac = base64_encode(hash_hmac('sha256', $data, SHOPIFY_APP_SECRET, true));
  return ($hmac_header == $calculated_hmac);
}

function sendMsg($id, $msg) {
  echo "id: $id" . PHP_EOL;
  echo "data: $msg" . PHP_EOL;
  echo PHP_EOL;
  ob_flush();
  flush();
}
$hmac_header = $_SERVER['HTTP_X_SHOPIFY_HMAC_SHA256'];
$data = file_get_contents('php://input');
$verified = verify_webhook($data, $hmac_header);
while (1) {
    if ($data !== "") {
        sendMsg("test id", "Data: " . $data);
    }
    sleep(1);
}
?>

当我将数据从 Shopify 推送到这个 PHP 脚本时,第一个 JavaScript 示例应该正在监听这些数据,但没有任何反应。不是一回事。我不知道为什么。我不知道如何告诉 PHP 脚本说:“嘿!有订单进来了!Yo JavaScript,做点什么!” 然后 JavaScript 运行,“收到新订单!让我们做点什么!”

TLDR:

  1. Shopify 将 JSON 推送到 PHP 脚本(通过 webhook)
  2. 单独的 JavaScript 文件通过 EventSource 对象监听这个 PHP 脚本并做出相应的反应
  3. 我不能让它工作。请帮忙。

就这些。谢谢你。

标签: javascriptphpeventsource

解决方案


我在 Twitter 上看到了这个——不,这个可以回答。

首先,我必须承认我对 EventSource 不太熟悉 - 但据我所知,您正在使用一个脚本同时做两件事;获取 Shopify 数据并立即将其导出到 JS。但是,每个运行的 PHP 脚本都只有一个请求和响应上下文 - 在这种情况下,您一直在将数据回显到 Shopify。

您将需要两个端点:

  1. 第一个端点充当 Shopify 的 webhook ( shopify_webhook.php) 的接收者。每次它接收到数据时,您都可以将其存储在数据库中以用于像 Redis 这样的即发即弃的操作,您可以在其中设置一个可能较低的 TTL。据我所知,Redis 也有队列——所以这可能是一个更好的方法。
  2. 第二个端点是您的事件源,它将传入队列条目流式传输到您的请求 JavaScript(即shopify_eventsource.php)。

这里的 Redis 只是一个建议 - 但无论如何,您必须使用中间存储才能将传入数据移动到另一个输出通道。您可以将所有这些写在一个 PHP 文件中,您可以在其中验证传入请求,以查看它是 Shopify 请求(和流)还是请求输出的 JavaScript 代码。但是,如果 Shopify 更改 API 或您自己的 JavaScript 接收者,使用两个端点并因此分离代码可能会使其更具可读性和可调整性。

TL;博士:

  1. Shopify -> Your endpoint -> intermediate storage.
  2. Intermediate storage -> your endpoint -(stream)> your javascript.

推荐阅读