本博客文章翻译自此篇
英文版,是关于SAP Event Mesh在SAP业务技术平台在中国(上海)区域(也即SAP Business Technology Platform on Alibaba Cloud)的应用教程,包括一个入门级的端到端的简单动手实验。所有的代码部分都可以在这个
代码仓库中找到,而理论部分主要可以参考这篇
帮助文档、这项
教程、这个
视频系列以及这篇
博客文章。
SAP Event Mesh在中国(上海)区域的的产品重命名还在进行中(原产品名为SAP Enterprise Messaging)。本文章将会随着此过程的进度做相应更新。
💻 您需要准备:
- 在SAP BTP中国(上海)区域的上的全局账户和子账户;
- SAP Event Mesh和SAP Business Application Studio的资源权利。
创建服务实例和租用多租户运用程序
首先,我们前往SAP BTP主控室,进行服务、资源和安全等配置。
权利配置
确保您的全局账户中有SAP Event Mesh 的如下资源权利,并将其分配到对应的子账户中:
服务 |
技术名称 |
服务计划 |
---|
Event Mesh |
enterprise-messaging |
default |
Enterprise Messaging |
enterprise-messaging-hub |
standard |
第一个服务用于创建消息客户端服务的实例,而第二个是可供租用的多租户业务应用程序,以便用户通过Web用户洁面来管理消息传递客户端和事件目录等。

服务实例
进入您CF的组织和空间中,选择
Event Mesh
服务,
default
计划,创建服务实例。
在弹出的向导中,您需要填入JSON格式的服务描述符(遵循语法
Syntax for Service Descriptor),你可以复制粘贴如下文本,然后修改相应参数:
{
"emname": "<message-client-name>", // fill in your message client name
"namespace": "<your-namespace>", // fill in your namespace
"version": "1.1.0",
"options": {
"management": true,
"messagingrest": true,
"messaging": true
},
"rules": {
"queueRules": {
"publishFilter": [
"${namespace}/*"
],
"subscribeFilter": [
"${namespace}/*"
]
},
"topicRules": {
"publishFilter": [
"${namespace}/*"
],
"subscribeFilter": [
"${namespace}/*"
]
}
}
}
🔖 除了使用主控室,您还可以使用CF CLI命令行来完成以上操作。
服务秘钥
为了创建服务秘钥,您需要前往主控室中,选择刚才创建好的服务实例
👉 为其创建服务秘钥
👉 输入秘钥名称
👉 点击创建。
您不需要输入秘钥的内容参数,系统会自动为您创建好。现在,查看自动创建的JSON格式的内容,找到如下内容:
- namespace 命名空间,
- management API URI和三个 messaging API URI (尤其注意 HTTP REST协议的URI),
- client id 客户端标识,,client secret 客户端秘钥以及token endpoint令牌端点。
稍后您将会用到它们。
多租户应用程序以及角色和用户分配
在主控室的“租用“页面,选择服务
Enterprise Messaging
(技术名: enterprise-messaging-hub),服务计划
standard
。

将相应角色添加到角色集合中,并将用户(在此教程中是您自己的SAP账号)添加到角色集合中。

现在,您可以在“
Event Mesh”的磁贴中,通过“转到应用程序”链接来打开 Event Mesh 业务应用程序的用户界面(Event Mesh Dashboard。您可以浏览该界面上的一些功能,比如,您可以打开您刚才创建的消息客户端,查看规则、队列等信息。
创建队列并且测试发布或者使用消息(通过用户界面)
创建
🎬 场景:您想要看央视春晚,尤其是里面的小品节目,但是比较忙,没办法全程守在电视机前看直播。于是希望CCTV给您发送消息,告诉您什么时候是什么节目正在上演,这样至少您稍后可以通过查看消息来查找您想看的节目。
您需要首先创建一个名为
comedy
的队列。在用户界面上,选择
Message Clients
页面
👉 选择消息客户端磁铁
mymessageclient
👉 选择
Queues
👉 选择
Create Queue
👉 在弹出窗口中,填入参数:queue name = comedy,其他参数置为默认值。

点击
Create
,您将会看到队列
myorg/mymessageclient/001/category
已经被创建了,但是还没有消息在队列中。
🔖 您无需再队列名前面加上命名空间作为前缀,因为系统将会自动为您加上。
测试
进入测试页面,在左边,选择队列与消息客户端,在
Message Data
中填入参数,点击
Publish Message
。您将会看到有通知提醒您消息已经发送,并且队列中消息的数量变为1。
📊 Message Data样例
- Content-Type: application/json
- Body: {"time": "20210124 21:00:00", "category": "music"}
在右边,选择队列与消息客户端,点击
Consume Message
。您会看到刚才发送的消息的内容,并且队列中消息的数量变为0。

通过API创建队列与发布和使用消息(通过Postman桌面应用程序)
🎬 场景:您的女儿也想要看春晚。她只关心她的偶像们何时出场,所以她希望CCTV能为她推送关于节目的演员的消息。
Event Mesh同时也提供了可以管理队列、队列租用的API——
REST APIs for Management,以及用于发送和接收消息的API——
REST APIs for Messaging。
我们使用Postman的桌面应用程序来发送HTTP 请求。现在您可以回想一下您创建完服务秘钥时查看的那些URI和标识符等。
获取访问令牌
在与Event Mesh的服务使用API通信之前,我们需要从XSUAA处获取访问令牌(access_token)。这篇
帮助文档将会指导您如何使用客户端标识和客户端秘钥,从令牌端点处获取访问令牌。
您需要在Postman里填写以下信息:
页面 |
键 |
值 |
---|
Bar |
Method |
选择GET |
Bar |
URL |
<tokenendpoint>?grant_type=client_credentials&response_type=token |
Authorization |
Type |
选择Basic Auth |
Authorization |
Username |
<clientid> |
Authorization |
Password |
<clientsecret> |
发送请求,您将会收到 200 OK 带有访问令牌的回复,您需要在后续的请求头中带入该访问令牌:
Authorization
:
Bearer {{access_token}}
。
创建队列
在上面给出的关于API的文档中,您可以找到用来创建队列的API
PUT /hub/rest/api/v1/management/messaging/queues/{queue}
。
在URL中的参数
{queue}
是经过网址编码的,并且加有命名空间作为前缀的队列全称,比如
myorg/mymessageclient/001/artist
经过编码后变为
myorg%2Fmymessageclient%2F001%2Fartist
。
您需要在Postman里填写以下信息:
页面 |
键 |
值 |
---|
Bar |
Method |
选择PUT |
Bar |
URL |
<management[0].uri>/hub/rest/api/v1/management/messaging/queues/{queue} |
Authorization |
Type |
选择No Auth |
Headers |
Authorization |
Bearer <access_token> |
请求体是可选的,如果您不提供请求体,系统将会使用
QueueP模式中的默认值。
发送请求,您将会收到201 Created带有已创建队列的信息的回复。
如果您想要获取某个队列的信息,您可以通过API
GET /hub/rest/api/v1/management/messaging/queues
。除了Method 和Path的值不同以外,其他的参数都与创建队列的参数相同。
发送与接收消息
为了能用API来向一个队列发送消息,我们可以从messaging API中找到API
POST /messagingrest/v1/queues/{queue-name}/messages
。 在URL中的参数
{queue-name}
同样应该是经过网址编码的带有命名空间作为前缀的队列全称。
页面 |
键 |
值 |
---|
Bar |
Method |
选择POST |
Bar |
URL |
<messaging[protocol=httprest].uri>/messagingrest/v1/queues/{queue-name}/messages |
Authorization |
Type |
选择No Auth |
Headers |
x-qos |
样例0 |
Headers |
Authorization |
Bearer <access_token> |
Body |
raw - JSON |
样例{"time": "20210124 21:00:00", "artists": [{"name": "TFBOYS"}, {"name": "Ye Zhang"}]} |
在请求头中,
x-qos
的意思是服务质量(quality of service,QoS), 0
表示服务将尝试传递消息,并且无论消息是否已传递,都将返回代码为 204 的 HTTP 响应。1
表示的是服务以 HTTP 响应代码 204 进行响应。如果未收到 204 响应代码,则客户端负责重新尝试,直到收到响应代码 204 为止。
在请求体中,您可以选择
raw
的类型,并且输入任何内容。如果您想要传输Cloud Event,您则需采用JSON的格式。
发送请求,您将会收到204 No Content的回复,并且消息的ID会被附在回复头中。

若要从队列中接收消息,您需要使用API
POST /messagingrest/v1/queues/{queue-name}/messages/consumption
。您可以使用与发送消息相同的请求头,并且将请求体置空。

在代码库里的文件夹
./apis
中,您将可以找到本动手实验在Postman中使用的请求的配置文件。
创建队列租用并向话题发送消息
🎬 场景:如果现在央视只发送一种关于节目的消息,同时含有节目类别和演员表的信息,您和您的女儿都对这一种消息感兴趣,但不幸的是,一条消息只能被一个人消费,如果您的女儿接收到了某条消息,那么您就接收不到了。此时,您需要让央视将消息发送到一个主题中,并且您和您的女儿各创建一个队列,来订阅这个话题,这样,您和您的女儿都能收到来自央视的消息,并且两人的消费行为互不影响。
通过用户界面为消息 artist
创建主题
您可以前往网页端的用户界面来创建主题,也即队列租用。请注意,您填入的主题的名称应该遵循您在服务描述(service descriptor)中的规则相一致,也即,名称的前缀命名空间应该与队列的相一致。

向主题发送消息
您可以在messaging API中找到用来发送给主题
performance
的API
POST /messagingrest/v1/topics/{topic-name}/messages
。
页面 |
键 |
值 |
---|
Bar |
Method |
选择POST |
Bar |
URL |
网址编码过的 <messaging[protocol=httprest].uri>/messagingrest/v1/topics/{topic-name}/messages |
Authorization |
Type |
选择No Auth |
Headers |
x-qos |
样例0 |
Headers |
Authorization |
Bearer <access_token> |
Body |
raw - JSON |
样例{"time": "20210124 21:05:00", "name": "A Funny Comedy", "category": "comedy", "artists": [{"name": "Ling Jia"}], "status": "START"} |
发送请求后,您将会在用户界面中看到,队列
artist
的消息数量增加了1。
通过API为队列 category
创建主题
我们使用management API
PUT /hub/rest/api/v1/management/messaging/queues/{queue}/subscriptions/{topic}
.
页面 |
键 |
值 |
---|
Bar |
Method |
选择PUT |
Bar |
URL |
网址编码过的 <management[0].uri>/hub/rest/api/v1/management/messaging/queues/{queue}/subscriptions/{topic} |
Authorization |
Type |
选择No Auth |
Headers |
Authorization |
Bearer <access_token> |

若主题被成功创建,您将会收到201 Created带有队列和主题信息的回复。
现在的体系结构为:

图片改编自 SAP Help Portal
通过API发布消息到主题并从队列消费消息
发布消息到主题,您需要在Postman中创建请求,并填入如下信息:
页面 |
键 |
值 |
---|
Bar |
Method |
选择POST |
Bar |
URL |
网址编码<messaging[protocol=httprest].uri>/messagingrest/v1/topics/{topic-name}/messages |
Authorization |
Type |
选择No Auth |
Headers |
x-qos |
样例0 |
Headers |
Authorization |
Bearer <access_token> |
Body |
raw - JSON |
样例{"time": "20210124 21:00:00", "name": "Go, Amigo and Hi, Motherland Mash Up", "category": "music", "artists": [{"name": "TFBOYS"}, {"name": "Ye Zhang"}], "status": "START"} |
发送消息后,您可以看到,两个队列均可接收到消息。
现在让我们来从两个队列中获取消息。

[选做] 在SAP BTP上开发消息生产者与消息使用者的应用程序(通过Node.js或者JAVA)
在此篇教程
Tutorial: Develop a Messaging App on SAP BTP 中,您可以学到如何开发运行在BTP上的Node.js或者JAVA消息生产者和使用者应用程序。
SAP为您提供了一系列的开发工具,例如 Node.js 包, Java 类库等等,使您能够开发可以
传递消息和通信的XS-Advanced应用程序(XS Advanced 即SAP HANA Extended Application Services advanced model,能使您的应用程序运行在由SAP改良的Cloud Foundry PaaS平台上)。
JavaScript
想要使用JavaScript开发,您可以参考
Standard Node.js Packages for XS Advanced:
- @Sisn/xb-msg: 此开发包提供了消息代理以及相关通信功能,可以支持RabbitMQ的消息代理,支持以下协议:AMQP v091, AMQP v100, MQTT v311;
- @Sisn/xb-msg-env: 此开发包提供了建立Cloud Foundry 或者XS Advanced环境下的消息客户端的相关函数;
- @Sisn/xsenv: 此包可用于简单地创建和获取XS Advance的环境变量和服务。
Java
想要使用Java来进行开发,您可以参考
SAP Cloud Application Programming Model(使用到的类库为com.sap.cloud.servicesdk.xbem.*),这个类库符合Java消息服务的一些标准 Java Message Service (JMS) 2.0 specification, :
- MessagingService,
- MessagingServiceJmsConnectionFactory,
- …
SAP Cloud SDK中的与Event Mesh有关的特性已经在计划之中,其进度依赖于CAP。
创建Webhook (nodejs),部署到CF,并租用到队列
🎬 场景:现在,您不想要时不时地查看您的队列是否有收到节目消息,并判断该节目是否是小品,您想要创建一个webhook,来主动从队列中获取消息,并为您记录只与小品有关的节目信息。
如果我们为消息系统添加一个webhook,那么就不是消息消。在此教程中,我们只为队列
comedy
创建一个webhook。

此图片改编自 SAP Help Portal
我们接下来会采用的样例改编自这个视频系列的第一部分
Youtube: Diving into messaging on SAP Cloud Platform (1-8)。
创建和部署
前往SAP Business Application Studio
👉 创建
Full Stack Cloud Application(全堆栈云应用程序)
类型的开发空间,命名为
emtester
,进入开发空间
👉 使用向导创建项目
👉 选择模板和工作区
Basic Multitarget Application
👉 Start
👉 输入项目名称
webhook
,完成。
您会看到系统有自动生成一些文档,请删除它们。创建一个名为
manifest.yml
的文档,复制粘贴如下内容到文档中:
---
applications:
- name: webhook
routes:
- route: <host-name>.<domain>
path: .
memory: 128M
替换应用程序名称(name)和路径(route)为您自己的值,比如,路径应为您为应用程序取的主机名(hostname)和域名(domain)的连接
webhook.exercise.sap-samples.cn40.apps.platform.sapcloud.cn
.
如果您不确定,您可以使用哪个域名,您可以在Business Application Studio 中打开Terminal
👉 cf login
👉 选择目标组织和空间
👉 使用
cf domains
命令列出您组织下的所有域名
👉 选择可用域名。
在Terminal 中,前往当前项目的根目录,运行
npm init
然后一直敲击回车键,使用默认值,直到最后输入OK。您将会看到,文件
package.json
已被创建,并且它需要一个主页文件
index.js
。
用命令
npm install express body-parser来安装所需的两个 Node.js 包,express和body-parser。
🔖 这两个包是做什么的?
express 用于为单网页应用程序、网站以及公共HTTP API提供轻巧而简装的HTTP服务器工具。
body-parser 用于在中间件中解析请求体。
在文件
package.json
中,我们通过在
scripts
中
添加键值对 start
来指定初始脚本,并删除 test
。 最终,我们得到的文件 package.json
长这样:
{
"name": "webhook",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"start": "node index.js"
},
"author": "",
"license": "ISC",
"dependencies": {
"body-parser": "^1.19.0",
"express": "^4.17.1"
}
}
现在,让我们来写
index.js
文件,请复制粘贴如下代码:
const express = require("express")
const bodyParser = require("body-parser")
const app = express()
const PORT = process.env.PORT || 8080
app.use(bodyParser.json())
app.get('/', (req, res) => {
res.status(401).send('Hey, this is a webhook - we only receive POST!')
})
app.post('/', (req, res) => {
if(req.body.category == "comedy") {
console.log(' ', req.body)
res.status(200).send(' ' + req.body.name).end()
}
else {
console.log(' ', req.body)
res.status(200).end()
}
})
app.listen(PORT, () => console.log(` Server running on port ${PORT}`))
[可选] 如果您想要再您的本地终端中先测试一下您的应用程序,您可以在项目根目录下,运行 npm start
,然后开一个新的标签页使用cURL来向localhost发送如下请求:
curl -H 'Content-Type: application/json' -d'{"time": "20210124 21:00:00", "name": "Go, Amigo and Hi, Motherland Mash Up", "category": "music", "artists": [{"name": "TFBOYS"}, {"name": "Ye Zhang"}], "status": "START"}' http://localhost:8080/
curl -H 'Content-Type: application/json' -d'{"time": "20210124 21:05:00", "name": "A Funny Comedy", "category": "comedy", "artists": [{"name": "Ling Jia"}], "status": "START"}' http://localhost:8080/
第一条指令将会使您的应用程序在控制台打印出哭脸,二第二条指令将会打印出笑脸。
接下来将您的应用程序部署到BTP上。在Terminal中,运行命令
cf push
。
如果要测试 webhook,使用Postman来向Webhook发送请求。

所有的关于webhook的代码可以在这个文件夹中找到
./webhook/
。
创造webhook租用
前往网页端用户界面
👉 前往消息客户端
👉 选择
webhooks
页面
👉 篡改建webhook 租用
👉 在弹出窗口中,填入队列名称,webhook的URL地址,和其他参数
👉 点击
create
.

激活的过程将会在消息客户端和webhook应用程序间的第一次握手
,也就是第一次通信时产生。

发送消息到主题 performance
并从webhook的日志中读取消息
再次发布两则消息到主题
performance
,消息内容参考我们在测试主题的时候发送的消息,您会发现,队列
artist
的消息数量发生了增加,然而队列
category
的消息数量仍然为零。这说明了发送给队列
category
的消息已经被
webhook消费了。
前往
cf logs webhook
查看日志,您会发现,刚才发送的两则消息被webhook消费后,分别留下了两条log,一条被标记为interested,另一条则是not interested。

如果您有将您的应用程序绑定一个SAP Apppication Logging Service 的服务实例(在
这篇文档您可以了解如何实现绑定),您还可以从BTP的主控室中的日志一页查看您应用程序的日志。

至此,您已经走完了SAP Event Mesh在中国(上海)区域的第一个端到端的场景。
参考资料