Webhook 通知

*此内容使用人工智能(Beta)翻译,可能包含错误。若要查看英文页面,请点按 此处

您可以通过设置 webhook 来接收实时通知,而不是手动监控您的体验和用户的请求,以及在第三方消息工具或自定义端点接收 HTTP 请求的自定义端点。这可以帮助您自动化通知管理工作流程,减少手动处理通知的工作量。

Webhook 工作流程

Webhook 将实时通知或数据发送到两个不同的应用或服务之间,例如 Roblox 和第三方消息工具。与传统 API 不同,它们将数据发送到您的客户端端口,当发生事件时,即可收到数据。它们对于您与您的团队合作以及在 Roblox 上使用的自动化工作流程的自动化非常有用。

当您设置了一个 webhook 后,每当目标事件发生时,Roblox 会向您提供的 webhook URL 发送请求。 webhook URL 会然后将请求发送到您提供的目标事件或自定义端口,这取决于 webhook 载入的数据。这可能包括清除数据,向用户发送确认或触发另一个事件。

支持的触发器

Roblox 目前支持以下事件触发器进行通知:

  • 订阅取消了 - 当用户取消订阅时,会发送一个包含订阅和订阅者的消息,以及原因为取消。
  • 订阅购买完成后 - 当用户购买订阅时,会发送包含订阅和订阅者的消息。
  • 订阅退款了 - 当用户收到订阅退款时,包含订阅和用户的消息。
  • 订阅已更新 - 当用户更新订阅时,会发送包含订阅和订阅者的消息。
  • 订阅重新订阅 - 当用户重新订阅时,会发送包含订阅和订阅者的消息。
  • “忘记权” 数据删除请求在《一般数据保护规则》( GDPR )下。

了解有关订阅事件和其字段的更多信息,请参阅云端 API 订阅

在创建者仪表板上配置 Webhook

要通过 webhook 接收通知,您需要配置一个订阅特定事件的 webhook 来触发通知。对于群组拥有的体验,只有群组所有者才能配置并收到 webhook 通知。

要设置 webhook:

  1. 导航到创建者仪表板的Webhook部分。
  2. 点击 添加Webhook 按钮。
  3. 完成配置领域:
    1. Webhook URL — 指定您想要接收通知的 URL 并接受第三方实体发出的 webhook URL。有关更多信息,请参阅设置 Webhook
    2. 名称 — 使用自定义名称来区分您的配置与其他人。 默认情况下,值与 Webhook 上传地址相同。
    3. 秘密 (可选) — 提供秘密,如果您想验证您收到的通知是否来自 Roblox。有关更多信息,请参阅验证 Webhook 安全
    4. 触发器) — 从事件列表中选择一个或多个选项以便接收通知。
  4. 点击 保存更改 按钮。

设置 Web 上的钩机器人 URL

您可以将自定义 HTTP 服务端设置为您的 webhook URL,提供它满足以下要求:

  • 它必须公开提供处理请求的功能。
  • 它可以处理 POST 请求。
  • 它可以在 5 秒内回应请求以 2XX 回应。
  • 它可以处理 HTTPS 请求。

当您的端点接收 POST 请求时,它必须能够:

  • 从 POST 消信息的身体中提取所需的细节。
  • 阅读与通知有关的事件类型的通知的通用细节,以及与通知相关的特定细节。

了解有关 POST 请手柄的更多信息,请参阅Payload Schema

交付失败重试政策

当网络接口不可用或其他错误导致 webhook 通知无法达到指定 URL 时,Roblox 会重试将消息发送到指定 URL 5 次,使用固定窗口大小。 如果通知仍然无法发送,Roblox 会停止尝试发送通知,并假设 URL 已失效。 在此情况

第三方要求

第三方工具通常有自己的Webhook配件需要您在设置Webhook URL时遵循。您可以通过搜索目标工具的支持或文档网站上的关键字“webhook”来找到这些要求。对于三个支持的第三方工具,请参阅以关注中/正在关注:

测试网络

您可以测试您配置的webhook是否能够在创建者仪表板上收到通知:

  1. 导航到Webhook配置页面。

  2. 选择您想要测试的网站从配置的网站中的 webhook 列表。

  3. 点击目标 webhook 旁边的铅笔图标。

    The pencil icon next to an example webhook
  4. 点击 测试反馈 按钮。

然后,系统发送一个通知在 SampleNotification 输入型,包括触发通知的用户的 用户ID ,如下示例脚本所示:

示例通知

Body: {
"NotificationId": "string",
"EventType": "SampleNotification",
"EventTime": "2023-12-30T16:24:24.2118874Z", // 类型:ISO 8601 时戳
"EventPayload": {
"UserId": 1 // 类型:长
}
}

如果您正在集成您的 webhook 与第三方服务,您可以使用第三方 URL 来确认服务可以成功接收来自您的 webhook 的通知。如果您在配置 webhook 时提供了秘密,它还会生成一个 roblox-signature ,您可以使用它来测试 webhook 逻辑。

验证网络安全

一旦您配置您的服务器接收载入,它就开始收听任何载入端的任何付载。如果您在配置您的webhook时设置了秘密,Roblox 将在每个webhook 通知中发送一个 roblox-signature 以帮助保护您的数据安全。 此方式,您可以使用它来验证从 Rob

Signature Format with Secret for Custom Endpoints

"roblox-signature": "t=<timestamp>,v1=<signature>"

如果您的Webhook没有秘密,您的签名只包含当通知发送时的时戳值:

Signature Format without Secret for Custom Endpoints

"roblox-signature": "t=<timestamp>"

要验证签名:

  1. 提取时戳和签名值。所有与秘密的网络接口的签名都使用与这两个值之间的前缀为 CSV 字符串格式:

    • t : 通知发送时的时戳值。
    • v1 : 签名值使用创建者仪表板配置提供的秘密生成。您可以使用 split() 函数,在此例中使用 , 角色,从字符串基于一致符号分离。
  2. 通过重创基础字符串 roblox-signature 来重创基础字符串:

    1. 时戳作为字符串。
    2. 时期角色 . .
    3. 请求身体的 JSON 字符串。
  3. 使用 SHA256 哈希函数使用您在配置中定义的秘密作为钥匙,并使用步骤 2 作为消信息生成的基本字符串,计算一个基于哈希的消息验证代码 (HMAC)。将结果转换为 Base64 格式,以获得您期望的签名。

  4. 比较抽取的签名值与预期的签名值。如果您正确生成了签名,值应该相同。

  5. (可选) 为了防止重播攻击,一种类型的黑客攻击,在攻击者接截和重发数据以获得未授权访问或执行恶意操作,它的帮助是比较抽取时间戳值与当前时间戳值,确保它落在合理的时间限制内。例如,10分钟窗口通常是一个良好的理想时间限制。

付费模式数据

当您的Webhook的目标事件触发时,它向您的Webhook URL发送请求,包括关于事件的载入信息。所有Webhook的请求都共享相同的 schema,其中包括固定和变量字段。这确保数据在Webhook中传输的数据是结构化的和一致的,使受信应用程序更容易处理和使用数据。

固定付加载场景 可以帮助保持所有 webhook 请求的一致性,并且支持以下几个可用的字段:

  1. NotificationId , string : 每次发送通知的唯一标识。如果同一个 NotificationId 被收到两次,它将被视为重复。
  2. EventType , string : 字符串代表触发通知的类型。
  3. EventTimetimestamp:一个准确的时戳,表示事件触发时间。

变量載入scheme field 为 webhook 提供了灵活性,这使 webhook 可以容纳各种类型的事件,包括:

  1. EventPayloadobject:包含与webhook触发有关的信息。EventType 结构由事件类型变化。

下面的例子显示了 Right To Erasure Request 事件的载货架构:

右侧清除请求示例数据库

Body:{
"NotificationId": "string",
"EventType": "RightToErasureRequest",
"EventTime": "2023-12-30T16:24:24.2118874Z",
"EventPayload": {
"UserId": 1, // 类型:长
"GameIds": [ // 类型:一个长度为长度为长度为长度为长度为长度为长度为长度为长度为长度为长度为长度为长度为长度为长度为长度为长度为长度为长度为长度为长度为长度为长度为长度为长度为长度为长度为长度为长度为长度为长度为长度为长度为长度为长度为长度为长度为长度为长度为长度为长度为长度为长度为长度为长度为长度为长度为长度为长度为长度为长度为长度为长度为长度为长度为长度为长度为长度为长度为长度为长度为长度为长度为长度为长度为长度为长度为长度为长度为长度为长度为长度为长度为长
1234, 2345
]
}
}

处理通知

如果您存储任何 个人识别信息(PII) ,例如用户的用户ID,您必须删除此信息,当用户提交此请求来�

如果您使用自定义端点作为您的 webhook 服务器而不是第三方工具,您可以从 webhook 载入中抽取数据主题以进行删除,并使用自己的自动化解决方案建立。 以下代码示例提供示例解决方案,并通过验证请求来从 Roblox 发出的:

Extracting PII from Payload

const crypto = require('crypto')
const express = require('express');
let app = express();
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
// This is a sample only code
app.all('/*', function (req, res) {
console.log('-------- New Request Seen -------');
// 1. Extract the timestamp and signature
const shared_secret = '<Your secret>' // This can be set as an environment variable
const hmac = crypto.createHmac('sha256', shared_secret)
const roblox_signature_header = req.headers['roblox-signature'].split(',')
// 'roblox-signature' is present in all requests:
// Timestamp(t) is present in all requests, however signature value(v1) is not set unless a secret is shared during the webhook configuration.
// Fetch header component at Index 0 -> 't=' and Index 1 -> 'v1='
const timestamp = roblox_signature_header.find(e => e.startsWith('t=')).substring(2);
const extracted_signature = roblox_signature_header.find(e => e.startsWith('v1='));
// 2. Prevent Replay attack: 300 seconds window
const request_timestamp_ms = timestamp * 1000;
const window_time_ms = 300 * 1000
const oldest_timestamp_allowed = Date.now() - window_time_ms;
if (request_timestamp_ms < oldest_timestamp_allowed) {
res.status(403).send('Expired Request')
}
// 3. Validate Signature
if (extracted_signature !== undefined) {
const signature_v1 = extracted_signature.substring(3);
const message = `${timestamp}.${JSON.stringify(req.body)}`
const base64_signature = hmac.update(message).digest('base64')
if (signature_v1 !== base64_signature) {
res.status(401).send('Unauthorized Request')
}
}
// 4. Your logic to handle payload
const payloadBody = req.body
const eventType = payloadBody['EventType']
if (eventType === 'RightToErasureRequest'){
const userId = payloadBody['EventPayload']['UserId']
const gameIds = payloadBody['EventPayload']['GameIds']
const gameIdString = gameIds.toString()
console.log(`The payload: UserId=${userId} and GameIds=${gameIdString}`)
// If you store PII in data stores, use the UserId and GameIds to make a data store call to delete the information.
}
// 5. Return Response
res.json({ message: 'Processed the message Successfully' });
})
app.listen(8080, function () {
console.log('This is a Sample application')
})