使用Mercure协议向客户端推送数据

编辑本页

异步作业已经完成或创建聊天应用程序是需要“推送”功能的典型用例。

欧宝娱乐app下载地址Symfony提供了一个简单的组件美居协议,专门为这类用例设计的。

Mercure是一种开放协议,用于从服务器向客户端发布更新。它是基于计时器的轮询和WebSocket的现代而有效的替代方案。

因为它建在上面服务器发送事件(SSE)Mercure在现代浏览器中是开箱即用的(旧版本的Edge和IE需要)一个polyfill),并有高层实现在许多编程语言中。

Mercure提供了一种授权机制,在检索丢失的更新时出现网络问题时自动重新连接,一个在线API,智能手机的“无连接”推送和自动发现(受支持的客户端可以通过特定的HTTP头自动发现和订阅给定资源的更新)。

Symfony集成支持所有这些特性。欧宝娱乐app下载地址

在这段录音中你可以看到Symfony web A欧宝娱乐app下载地址PI如何利用Mercure和API平台来实时更新一个React应用程序和一个使用API平台客户端生成器生成的移动应用程序(React Native)。

为了管理持久连接,Mercure依赖于一个集线器:一个专门处理与客户端的持久SSE连接的服务器。Symf欧宝娱乐app下载地址ony应用程序将更新发布到中心,中心将广播给客户端。

多亏了Symfony的Docker集成欧宝娱乐app下载地址0b足球 建议安装一个美居中心。运行docker-compose起来如果选择此选项,则启动中心。

如果你使用欧宝娱乐app下载地址Symfony本地Web服务器,你必须从。开始——no-tls选择。

1
欧宝娱乐app下载地址Symfony服务器:启动——no-tls -d

环境变量

安装MercureBundle后,将.env你的项目文件已经被Flex配方更新到包含可用的env变量。

此外,如果您正在使用Docker与Symfony本地Web服务器的集成,欧宝娱乐app下载地址欧宝娱乐app下载地址Symfony码头工人或者是API平台分布时,已自动设置适当的环境变量。直接跳到下一节。

的值设置集线器的URLMERCURE_URL而且MERCURE_PUBLIC_URLenv var。有时,Symfony应用程序(通常用于发布)和JavaScript客户端(通常用于订阅)必须调用欧宝娱乐app下载地址不同的URL。当Symfony应用程序必须使用本地URL而客户端JavaScr欧宝娱乐app下载地址ipt代码必须使用公共URL时,这种情况尤其常见。在这种情况下,MERCURE_URL必须包含Symfony应用程序使用的本地URL(例如:欧宝娱乐app下载地址https://mercure/.well-known/mercure),MERCURE_PUBLIC_URL公开可用的URL(例如:https://example.com/.well-known/mercure).

客户还必须承担JSON Web令牌(JWT)向Mercure Hub授权发布更新,有时还授权订阅。

此令牌必须使用与Hub用于验证JWT (ChangeThisMercureHubJWTSecretKey !如果你使用Docker集成)。此密钥必须存储在MERCURE_JWT_SECRET环境变量。MercureBundle将使用它自动生成和签署所需的jwt。

除了这些环境变量,MercureBundle还提供了一个更高级的配置:

  • 秘密:用于签署JWT的密钥-必须使用与哈希输出相同大小的密钥(例如,256位的“HS256”)或更大的密钥。(所有其他选择,除了算法订阅,发布将被忽略)
  • 发布:生成JWT时允许发布的主题列表(仅在秘密,或工厂提供)
  • 订阅:生成JWT时允许订阅的主题列表(仅在秘密,或工厂提供)
  • 算法:用于签名JWT的算法(仅在秘密提供)
  • 提供者:要调用的服务ID,以提供JWT(所有其他选项将被忽略)
  • 工厂:要调用的服务ID以创建JWT(除了订阅,发布将被忽略)
  • 价值:要使用的原始JWT(所有其他选项将被忽略)
  • YAML
  • XML
  • PHP
12 3 4 5 6 7 8 9 10 11 12 13
#配置/包/ mercure.yaml美居酒店:中心:默认值:url:https://mercure-hub.example.com/.well-known/mercurejwt:秘密:“ChangeThisMercureHubJWTSecretKey !”发布:(“foo”,“https://example.com/foo”订阅:['酒吧',“https://example.com/bar”算法:“hmac.sha256”供应商:“我的\提供者”工厂:“我的\工厂”值:“my.jwt”

提示

JWT有效负载必须至少包含以下结构,客户端才能被允许发布:

1 2 3 4 5
“水银”: {“发布”: []}}

由于数组是空的,Symfony应用程序将只被授权发布公共更新(请欧宝娱乐app下载地址参阅授权部分以获取更多信息)。

jwt。io网站是一个方便的方式创建和签署jwt。签出这JWT例子该法案授予所有人出版权利主题(注意数组中的星号)。不要忘记在表单的右面板底部正确地设置您的密钥!

更新值对象表示要发布的更新。它还提供了出版商服务将更新发送到中心。

出版商服务可以使用自动装配在任何其他服务中,包括控制器:

12 3 4 5 6 7 8 9 10 11 12 13 14 16 17 18 19 20 21 22
/ / src /控制器/ PublishController.php名称空间应用程序控制器使用欧宝娱乐app下载地址FrameworkBundle控制器AbstractController使用欧宝娱乐app下载地址组件HttpFoundation响应使用欧宝娱乐app下载地址组件美居酒店HubInterface使用欧宝娱乐app下载地址组件美居酒店更新PublishController扩展AbstractController公共函数发布(HubInterface中心响应更新更新(“https://example.com/books/1”, json_encode (“状态”= >“OutOfStock”)));中心->发布(更新);返回响应(“发表!”);}}

对象传递的第一个参数更新构造函数是主题被更新。这个话题应该是一个IRI(国际化资源标识符,RFC 3987):被分派资源的唯一标识符。

通常,此参数包含传输到客户端的资源的原始URL,但它可以是任何字符串或IRI,它不必是一个存在的URL(类似于XML名称空间)。

构造函数的第二个参数是更新的内容。它可以是任何东西,以任何格式存储。但是,建议以超媒体格式(如JSON-LD、Atom、HTML或XML)序列化资源。

美居酒店()Twig函数根据配置生成Mercure hub的URL。URL包含主题查询与作为第一个参数传递的主题对应的参数。

如果你想从外部JavaScript文件访问这个URL,在一个专用的HTML元素中生成URL:

1 2 3
<脚本类型“application / json”id“mercure-url”>{{美居酒店|(“https://example.com/books/1”)json_encode常数(“JSON_UNESCAPED_SLASHES”)b或常数(“JSON_HEX_TAG”)) |}}脚本>

然后从JS文件中检索它:

1 2 3
常量url =JSON.parse (文档.getElementById (“mercure-url”) .textContent);常量eventSource =EventSource (url);/ /……

Mercure还允许订阅多个主题,并使用URI模板或特殊值(与所有主题匹配)作为模式:

12 3 4 5 6 7 8 9 10 11 12
<脚本>{#订阅几个Book资源和所有匹配给定模式的Review资源的更新#}常量eventSource =EventSource ({{水银([' https://example.com/books/1 ', ' https://example.com/books/2 ', ' https://example.com/reviews/ {id} ']) |逃避(js)}}”);eventSource。onmessage =事件= >{控制台.log(JSON.parse(event.data)); }脚本>

提示

谷歌Chrome开发工具本机集成一个实用的用户界面实时显示接收到的事件:

使用它:

  • 打开DevTools
  • 选择“网络”选项卡
  • 单击到Mercure集线器的请求
  • 点击“EventStream”子选项卡。

提示

测试URI模板是否与使用的URL匹配在线调试器

链接HTTP报头。

你可以创建链接的头文件发现Helper类(在底层,它使用连接组件):

12 3 4 5 6 7 8 9 10 11 12 13 14 16 17 18 19 20 21
/ / src /控制器/ DiscoverController.php名称空间应用程序控制器使用欧宝娱乐app下载地址FrameworkBundle控制器AbstractController使用欧宝娱乐app下载地址组件HttpFoundationJsonResponse使用欧宝娱乐app下载地址组件HttpFoundation请求使用欧宝娱乐app下载地址组件美居酒店发现DiscoverController扩展AbstractController公共函数发现(请求请求,发现发现JsonResponse//链接:;rel = "美居酒店"发现->通过addLink (请求);返回->json ([“@ id”= >“/书籍/ 1”“可用性”= >“https://schema.org/InStock”]);}}

然后,这个头可以在客户端解析,以找到Hub的URL,并订阅它:

12 3 4 5 6 7 8 9 10 11 12 13 14
//获取Symfony web API服务的原始资源欧宝娱乐app下载地址fetch (“/书籍/ 1”//有链接:;rel = "美居酒店"不要犹豫(响应= >//从Link头中提取hub URL常量hubUrl = response.headers.get(“链接”) .match (/<([^>]+)>;\ s + rel =(?:美居酒店|“^”*水银[^]*)/) [1];//添加主题订阅作为查询参数常量中心=URL (hubUrl,窗口.origin);hub.searchParams.append (“主题”“https://example.com/books/ {id}”);//订阅更新常量eventSource =EventSource(中心);eventSource。onmessage =事件= >控制台. log (event.data);});

更新构造函数真正的

12 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
/ / src /控制器/ Publish.php名称空间应用程序控制器使用欧宝娱乐app下载地址FrameworkBundle控制器AbstractController使用欧宝娱乐app下载地址组件HttpFoundation响应使用欧宝娱乐app下载地址组件美居酒店更新PublishController扩展AbstractController公共函数发布(HubInterface中心响应更新更新(“https://example.com/books/1”, json_encode (“状态”= >“OutOfStock”]),真正的/ /私有);//发布者的JWT必须包含该主题,它匹配的URI模板或*在mercure中。出版,否则你就得退休了//订阅者的JWT必须包含该主题、它匹配的URI模板或mercure中的*。订阅以接收更新中心->发布(更新);返回响应(“私人更新已发布!”);}}

要订阅私有更新,订阅者必须向Hub提供包含与更新主题匹配的主题选择器的JWT。

要提供这个JWT,订阅者可以使用cookie或授权HTTP报头。

通过将适当的选项传递给欧宝娱乐app下载地址美居酒店()树枝的功能。由Symfony设置的cook欧宝娱乐app下载地址ie被浏览器自动传递到Mercure中心withCredentials属性。EventSource类设置为真正的.然后,Hub验证所提供的JWT的有效性,并从中提取主题选择器。

1 2 3 4 5
<脚本>常量eventSource =EventSource ({{mercure('https://example.com/books/1', {subscribe: 'https://example.com/books/1'})|逃避(js)}}, {withCredentials: true});脚本>

支持的选项有:

  • 订阅的主题选择器列表mercure.subscribeJWT的声明
  • 发布的主题选择器列表mercure.publishJWT的声明
  • additionalClaims: JWT中包含的额外声明(过期日期,令牌ID…)

当客户端是web浏览器时,使用cookie是最安全和首选的方式。如果客户端不是web浏览器,那么使用授权标头是正确的方法。

谨慎

要使用cookie身份验证方法,Symfony应用程序和Hub必须从相同的域(可以是不同的欧宝娱乐app下载地址子域)提供服务。

提示

EventSource的本机实现不允许指定头文件。例如,使用承载令牌进行授权。为了达到这个目的,使用一个polyfill

1 2 3 4 5 6 7
<脚本>常量es =EventSourcePolyfill ({{mercure('https://example.com/books/1')}}, {headers: {'Authorization': ' holder ' + token,}});脚本>

然后,创建以下实体就足以获得一个全功能的超媒体API,并通过Mercure hub自动更新广播:

12 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
/ / src /实体/ Book.php名称空间应用程序实体使用ApiPlatform核心注释ApiResource使用学说ORM映射作为ORM# (ApiResource(水银:真)]# (ORM \实体)# (ORM \ Id)# (ORM \列)公共字符串的名字# (ORM \列)公共字符串状态;}

作为展示在这段录音中, API平台客户端生成器还允许从这个API构建完整的React和React Native应用程序。这些应用程序将实时呈现Mercure更新的内容。

结帐专用的API平台文档欧宝体育电话以了解更多有关Mercure的支持。

对于功能测试,您可以创建Hub的存根:

12 3 4 5 6 7 8 9 10 11 12 13 14 15
/ /测试/功能/存根/ HubStub.php名称空间应用程序测试功能存根使用欧宝娱乐app下载地址组件美居酒店HubInterface使用欧宝娱乐app下载地址组件美居酒店更新HubStub实现了HubInterface公共函数发布(更新更新字符串返回“id”;}//实现HubInterface的其他方法

使用HubStub替换默认的集线器服务,这样实际上就不会发送更新:

1 2 3
#配置/ services_test.yamlmercure.hub.default:类:应用\ \ \存根\ HubStub功能测试

由于MercureBundle支持多个集线器,您可能必须相应地替换其他服务定义。

在您的配置中启用面板,如下所示:

MercureBundle附带一个调试面板。安装调试包以启用它:

1
编译器需要——开发symfony/调试包欧宝娱乐app下载地址

提示

不鼓励使用异步调度。大多数Mercure中心已经异步处理发布,通常不需要使用Messenger。

而不是调用出版商由于提供了与Messenger组件的集成,您还可以让Symfony异步欧宝娱乐app下载地址调度更新。

首先,要确定安装Messenger组件并正确配置传输(如果不这样做,将同步调用处理程序)。

然后,派遣美居号更新发送到信使的消息总线,它将被自动处理:

12 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
/ / src /控制器/ PublishController.php名称空间应用程序控制器使用欧宝娱乐app下载地址FrameworkBundle控制器AbstractController使用欧宝娱乐app下载地址组件HttpFoundation响应使用欧宝娱乐app下载地址组件美居酒店更新使用欧宝娱乐app下载地址组件信使MessageBusInterfacePublishController扩展AbstractController公共函数发布(MessageBusInterface公共汽车响应更新更新(“https://example.com/books/1”, json_encode (“状态”= >“OutOfStock”)));//同步或异步(Doctrine, RabbitMQ, Kafka…)公共汽车->调度(更新);返回响应(“发表!”);}}

通知器组件.使用它向web浏览器发送推送通知。
  • 欧宝娱乐app下载地址Symfony UX Turbo是一个库,使用Mercure提供与单页应用程序相同的体验,但不需要写一行JavaScript!
  • 此工作,包括代码示例,是根据创作共用BY-SA 3.0许可证。
    欧宝娱乐app下载地址Symfony 6.2支持通过苏禄人
    欧宝娱乐app下载地址Symfony 6.2支持通过Les-Tilleuls.coop
    写代码就行,剩下的就交给我们了"></a>
          <p class=写代码就行,剩下的就交给我们了

    测量和改进Symfony代码性能欧宝娱乐app下载地址"></a>
          <p class=测量和改进Symfony代码性能欧宝娱乐app下载地址

    检查开发、测试、阶段和生产阶段的代码性能"></a>
          <p class=检查开发、测试、阶段和生产阶段的代码性能