Symfony 5.4 - 我应该如何使用 symfony 正确启动 mercure

Symfony 5.4 - How am i supposed to properly start mercure using symfony

我按照文档中的说明使用以下命令安装了 mercure:

composer require mercure

之后,我应该启动 mercure 服务器,问题是:如何?

Symfony 的文档没有说明这一点。
Mercure 的文档也没有说明任何相关内容,尤其是使用在 /config/packages/mercure.yaml.

中生成的配置文件

我发现我需要下载一个单独的二进制文件(针对我的特定平台),然后我应该使用以下命令从 Powershell 启动服务器:

.\/bin/mercure run

但是,如果我尝试传递 -envfile ".env",那么它甚至不会尝试使用其中的任何变量。
最重要的是,它似乎根本没有使用任何环境变量,即使是我在 cmd 中定义的变量。

还有其他事情,比如我如何允许 CORS,因为我的配置文件中没有我可以更改的东西,它不是我可以传递给二进制文件的参数,我不能将它添加为一个环境变量。

如果我尝试订阅该事件(这是在 2019 端口上完成的,导致之前的问题),404 和 CORS 将被返回。

这也是我用 .\/bin/mercure run:

得到的

我的.env:

现在我想知道我应该如何使用 mercure,我看了几个 symfony 5.4 的视频,它们基本上都在 linux 上并且它以某种方式对他们有用或者它被标记作为配置更改、语法更改和其他的过时原因...

文档在这方面也没有任何帮助,这让我后悔尝试使用 mercure。

编辑:

有人告诉我尝试摆弄 Caddy 配置,但 mercure 似乎也没有尝试使用它们,甚至尝试使用 -config.

指定配置

结果:

Caddyfile:

    # Learn how to configure the Mercure.rocks Hub on https://mercure.rocks/docs/hub/config
{
    {$GLOBAL_OPTIONS}
    http_port 3000
    https_port 3000
}

localhost:3000

route {
    encode zstd gzip

    @origin header Origin http://localhost:8000
    header @origin Access-Control-Allow-Origin "http://localhost:8000"
    header @origin Access-Control-Request-Method GET
    header Access-Control-Allow-Credentials "true"

    mercure {
        # Publisher JWT key
        publisher_jwt "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJtZXJjdXJlIjp7InB1Ymxpc2giOlsiKiJdfX0.iHLdpAEjX4BqCsHJEegxRmO-Y6sMxXwNATrQyRNt3GY"

        subscriber_jwt "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJtZXJjdXJlIjp7InN1YnNjcmliZSI6WyIqIl19fQ.0J4jgLQSHzPMTZ5jiYM8Yv7jmTANRgILG5FKY98LgEU"

        publish_origins *
        # Extra directives
        {$MERCURE_EXTRA_DIRECTIVES}
    }

    respond /healthz 200

    respond "Not Found" 404
}

在这一点上,我觉得我正在使用书中的所有技巧,但它仍然不起作用,我可能最终会改用定期获取,可靠且实际工作。

更新 1:

更新 2:

没有 HTTP 错误,事件显然是从 mercure 所说的订阅,但没有收到任何东西,告诉我 mercure 不支持语义

更新 3:

在更新中设置了诸如/update/test/{0}的主题,事件源和yaml配置,客户端没有收到更新

更新 4:

无论有没有语义,我根本无法让更新工作,这是我的配置和路由 atm:

mercure.yaml :

mercure:
    hubs:
        default:
            url: '%env(MERCURE_URL)%'
            public_url: '%env(MERCURE_PUBLIC_URL)%'
            jwt:
                secret: '%env(MERCURE_JWT_SECRET)%'
                publish: '["/update/test/*"]'
                subscribe: '["/update/test/*"]'

我的路线(默认控制器):

#[Route('/update/test/{id}', name: 'test')]
public function test(HubInterface $hub, ?int $id): Response
{
    $update = new Update("localhost:8000/update/test/{$id}",
    son_encode(
        array(
                 "result" => "success",
                 "data" => "User is in Room {$id}"
             )
        )
    );

    $hub->publish($update);

    return new Response("Success");
}

我会给你一个 mercure 运行ning over windows 不使用 Docker 的例子,对不起我的英语好吗?!!

我将从使用 SSL 虚拟主机安装 symfony 5.4 开始:https://myshop.local 和 MercureBundle。

目标是当新产品进入商店库存时通知所有经过身份验证的用户。

首先:mercure hub 和您的站点必须 运行 在同一域或子域上,否则无法共享 auth cookie;所以我们的 mercure hub 将 运行 on https://myshop.local:3000(同一个域,但另一个端口,检查你的防火墙)

其次:需要设置合适的环境变量,所以在你的.env.local:

###> symfony/mercure-bundle ###
# See https://symfony.com/doc/current/mercure.html#configuration
# The URL of the Mercure hub, used by the app to publish updates (can be a local URL)
MERCURE_URL=https://myshop.local:3000/.well-known/mercure
# The public URL of the Mercure hub, used by the browser to connect
MERCURE_PUBLIC_URL=https://myshop.local:3000/.well-known/mercure
# The secret used to sign the JWTs
MERCURE_JWT_SECRET=m3rcu353cr37pa55pra53DEV
###< symfony/mercure-bundle ###

第三:Mercure 它基于主题概念(如频道),因此您的 mercure.yaml 食谱:

mercure:
    hubs:
        default:
            url: '%env(MERCURE_URL)%'
            public_url: '%env(MERCURE_PUBLIC_URL)%'
            jwt:
                secret: '%env(MERCURE_JWT_SECRET)%'
                publish: ['notif/new-on-stock'] # the topic or topics where the notifications will be published coming from the mercure hub.
                subscribe: ['notif/new-on-stock'] # the topic or topics to which users will subscribe to receive notifications.

第四:需要下载mercure的Windows二进制文件,并在Caddy文件中设置一些配置:

# Learn how to configure the Mercure.rocks Hub on https://mercure.rocks/docs/hub/config
{
    {$GLOBAL_OPTIONS}
}

{$SERVER_NAME:myshop.local:3000}

log

tls C:\wamp64\bin\apache\apache2.4.41\conf\ssl\myshop.local.crt C:\wamp64\bin\apache\apache2.4.41\conf\ssl\myshop.local.key

route {
    encode zstd gzip

    mercure {
        # Transport to use (default to Bolt)
        transport_url {$MERCURE_TRANSPORT_URL:bolt://mercure.db}
        # Publisher JWT key
        publisher_jwt {env.MERCURE_PUBLISHER_JWT_KEY} {env.MERCURE_PUBLISHER_JWT_ALG}
        # Subscriber JWT key
        subscriber_jwt {env.MERCURE_SUBSCRIBER_JWT_KEY} {env.MERCURE_SUBSCRIBER_JWT_ALG}
        cors_origins https://myshop.local
        publish_origins https://myshop.local
        # Extra directives
        {$MERCURE_EXTRA_DIRECTIVES}
    }

    respond /healthz 200

    respond "Not Found" 404
}

这里有三个重要方面:

  1. $SERVER_NAME
  2. tls 指令:您必须设置 .crt 和 .key 的路径 您的虚拟主机的 SSL 证书文件。
  3. cors_originspublish_origins 必须将您的 webapp 域设置为 避免 CORS 错误

第五:你必须 运行 你的 mercure 服务器 shell;从你的 mercure 二进制目录 运行: $env:MERCURE_PUBLISHER_JWT_KEY='m3rcu353cr37pa55pra53DEV';$env:MERCURE_SUBSCRIBER_JWT_KEY='m3rcu353cr37pa55pra53DEV';.\mercure.exe run -config .\Caddyfile

重要!!: 该密钥与环境变量 MERCURE_JWT_SECRET

相同

现在,您必须从控制器发布关于主题的通知:

public function publishNewProductAction(Symfony\Component\Mercure\HubInterface $mercureHub):Response{
           /** insert new product to a database **/
             ...
          $em->persist($newProduct);
          $em->flush();
    
        $data=['productName'=>$newProduct->getName(), 'productPrice'=>$newProduct->getPrice()];
    
          $update = new Symfony\Component\Mercure\Update();
          $hubUpdate = new Symfony\Component\Mercure\Update(
                'notif/new-on-stock', # the topic where you go to publish
                \json_encode($data), # the data that you want to publish on the mercure hub
                true # indicate that need auth
        );
        
        return new Response('A new product has been registered!!'); # its the normal response to user that insert a product (admin user for exmple)
        }

重要:symfony 创建 real-time 通知系统的真正力量在于将 Messenger 组件和异步队列与 Mercure 相结合。你可以调查一下。

因此,例如在客户端:

<script type="text/javascript">
                $(document).ready(function () {

                        const eventSource = new EventSource("{{ mercure('notif/new-on-stock', { subscribe:'notif/out-of-stock'})|escape('js')}}", {withCredentials: true});

                        eventSource.onopen = function () {
                            console.log('Socket connection!');
                        };

                        eventSource.onmessage = function (e) {
                            var data = JSON.parse(e.data);
                            console.log('A new product is enable for you: '+data.productName+'. Price: $'+data.price);
                        };

                        eventSource.onerror = function () {
                            console.log('Socket error!');
                        };

                    });
            </script>

您有一些错误。 首先:在你的 mercure.yaml 中,你必须以这种方式建立主题:

publish: ["update/test/{id}"] # your topic must complie with this format
subscribe: ["update/test/{id}"]

在您的环境变量中,您设置了 MERCURE_JWT_SECRET,以及 mercure.yaml 中声明的主题和订阅者,symfony-mercure-bundle 完成了传递给中心的 JWT,您不需要不需要将其设置到 de Caddy 文件中。

并且,在您的函数中:

#[Route('/update/test/{id}', name: 'test')]
public function test(HubInterface $hub, ?int $id): Response
{
    $update = new Update(sprintf("update/test/%s", $id)),
    json_encode(
        array(
                 "result" => "success",
                 "data" => sprintf("User is in Room %s", $id)
             )
        )
    );

    $hub->publish($update);

    return new Response("Success");
}

考虑到作为Update参数传递的URI段,不包含字符'{}'