網絡通知

*此內容是使用 AI(Beta 測試版)翻譯,可能含有錯誤。若要以英文檢視此頁面,請按一下這裡

您可以設定網絡呼叫來接收來自第三方即時通訊工具或自訂終端的 HTTP 請求的實時通知,而不是手動監控體驗中的所有事件和來自使用者的請求。這可以幫助您自動化通知管理工作流程,減少手動處理通知的勞力。

網路呼叫工作流程

網絡呼叫可在兩個不同應用程式或服務之間發送實時通知或資料,例如 Roblox 和第三方傳訊工具。與傳統 API 不同,網絡呼叫會在發生事件時立即將資料傳送到您的客戶端端點。它們對於自動化 Roblox 與第三方應用程式之間的工作流程有用,因為它們允許實時資料分享和處理,可以用於與團隊合作。

一旦您設定了網絡呼叫,每當目標事件發生時,Roblox 都會向您提供的網絡呼叫 URL 發送請求。網絡端點URL會將請求重定向到你的接收應用程式或自訂終點,這些應用程式或終點可以根據網絡端點載入的資料來執行行動。這可能包括為GDPR刪除數據、向用戶發送確認或觸發另一個事件。

支持的觸發器

Roblox 目前支持以下事件觸發器。

訂閱

  • 訂閱重新訂閱 - 當使用者重新訂閱訂閱時,會傳送包含訂閱和訂閱者的訊息。
  • 續訂訂閱已更新 - 當使用者續訂訂閱時,會傳送包含訂閱和訂閱者的訊息。
  • 訂閱退款 - 當使用者收到訂閱退款時,會傳送包含訂閱和訂閱者的訊息。
  • 已購買訂閱 - 當使用者購買訂閱時,會傳送包含訂閱和訂閱者的訊息。
  • 訂閱取消了 - 當使用者取消訂閱 訂閱 時,會傳送包含訂閱和訂閱者以及取消理由的訊息。

有關訂閱事件和其欄位的更多資訊,請參閱訂閱參考。

遵守

  • 刪除請求權 - 當使用者在《一般資料保護規則》(GDPR)下提交數據刪除請求時。

商業

  • 商業產品訂單退款 - 當使用者已收到商業產品訂單退款,或訂單已被取消時。
  • 商業產品訂單已付款 - 當使用者已付費購買其商業產品訂單時。請注意,重複的網絡事件是可能的,因此您應該使用獨特的商業訂單ID來刪除事件。

在創作者面板上配置網路鉤點

若要通過網絡通道接收通知,您需要配置一個網絡通道,訂閱特定事件以發出通知。對於團體擁有的體驗,只有團體所有者可以配置和接收網絡通知。

要設定網路呼叫:

  1. 前往創作者面板的 Webhooks 部分。
  2. 點擊 添加Webhook 按鈕。
  3. 完成配置欄位:
    1. Webhook URL - 指定您想收到通知的URL。有關需求的更多信息,請參閱設置網絡URL
    2. 名稱 - 使用自訂名稱來區分您的配置與其他人。默認值與 Webhook URL 相同。
    3. 秘密 (可選) - 提供秘密,如果你想要驗證你收到的通知來自 Roblox。欲了解更多信息,請參閱驗證Webhook安全
    4. 觸發器 - 從事件的支援觸發器列表中選擇一個或多個選項來接收通知。
  4. 按一下 儲存變更 按鈕。

設定網路請求URL

您可以設定自訂 HTTP 服務端點作為您的網絡呼叫 URL,只要它符合以下要求:

  • 必須公開存取以處理請求。
  • 它可以處理POST請求。
  • 它可以在 5 秒內回應請求以 2XX 回應。
  • 它可以處理 HTTPS 請求。

當您的終端點收到 POST 請求時,必須能夠:

  • 從 POST 訊息的主體中提取所需的通知細節。
  • 閱讀 POST 訊息的主體,包括通知的一般細節和與通知相關的事件類型的特定細節。

要了解有關處理POST請求的 Schema的更多信息,請參閱付載 Schema

交付失敗重試政策

當網絡通知因端點不可用等錯誤無法達到指定的 URL 時,Roblox 將使用固定窗口尺寸重試將訊息傳送到指定的 URL 5 次。如果通知仍然在 5 次嘗試後仍未能交付,Roblox 將停止嘗試發送通知,並假設 URL 已過期。在這種情況下,您需要使用新的可訪問且能夠接收通知的 URL 來更新您的網絡配置。若要排除故障並確認您的網絡URL可以成功接收通知,請參閱測試網絡

第三方需求

第三方工具通常會有自己需要遵循的網絡hook要求,當設置您的網絡hook URL時。您可以在目標工具的支持或文件網站上搜尋關鍵字「webhook」來找到這些需求。對於三個支持的第三方工具,請參見以下內容:

測試網絡端點

您可以測試您配置的網絡是否能在 創作者面板 上成功接收通知:

  1. 導航到 Webhooks 配置頁面。
  2. 從配置的網路請求清單中選擇要進行測試的網路請求。
  3. 點擊目標網絡鉤旁邊的筆記符號。
  4. 按一下 測試回應 按鈕。

系統然後發送一個 SampleNotification 事件,包括啟動通知的用戶的 使用者ID ,如下所示:

樣本通知架構

{
"NotificationId": "string",
"EventType": "SampleNotification",
"EventTime": "2023-12-30T16:24:24.2118874Z",
"EventPayload": {
"UserId": 1
}
}

如果您將網絡通道與第三方服務整合,您可以使用第三方URL測試它,以確認服務可以成功接收來自網絡通道的通知。如果您在配置網絡時提供秘密,它也會生成一個 roblox-signature 可用於測試 roblox-signature 邏輯。

驗證網路端點安全

配置完成後,您的伺服器開始聆聽端點發送的任何付載物,以便接收付載物。如果您在配置網絡時設置秘密,Roblox將在每個網絡通知中發送roblox-signature以確保請求實際來自 Roblox。簽名位於自定義終端的付載頭和第三方伺服器的腳尾中。

Signature format with a secret for custom endpoints

t=<timestamp>,v1=<signature>

如果你沒有為你的網絡設置秘密,簽名只包含通知發送時間戳:

Signature format without a secret for custom endpoints

t=<timestamp>

要驗證簽名:

  1. 提取時間戳和簽名值。所有擁有秘密的網絡通道簽名都與 CSV 字串的格式相同,其後面兩個值跟前缀一樣:

    • t : 通知發送的時間戳。
    • v1 : 使用創作者面板配置提供的秘密生成的簽名值。
  2. 重新創建 roblox-signature 的基礎字串,通過concatenation:

    1. 時戳以字串形式。
    2. 期間字元 .
    3. 請求體的 JSON 字串。
  3. 使用配置期間定義的秘密和步驟 2 生成的基本字串來計算基於哈希的訊息驗證代碼 (HMAC),使用 SHA256 哈希功能驗證訊息。將結果轉換為 Base64 格式以獲得預期的簽名。

  4. 將提取的簽名值與預期的簽名進行比較。如果您正確生成了簽名,值應相同。

  5. (可選) 為了防止重播攻擊,一種類型的網路攻擊,在攻擊者中間截取並重新傳送數據以獲得未經授權的存取或執行惡意行動,與當前時間戳比較提取的時間戳值有助於確保它在合理的時間限制內。例如,10 分鐘的窗口通常是一個很好的合理時間限制。

付載計畫表

當您的網絡通道目標事件被觸發時,它會向您的網絡通道URL發送一個請求,包括付載中事件的信息。所有請求的付載都共享相同的 schema,包括固定和變量欄位。這樣可以確保在載入時傳送的數據結構化且一致,使接收應用程式更容易處理和使用數據。 固定載入樣板欄位 可幫助維持所有網路請求的一致性,可用以下欄位:

  1. NotificationId (字串):每次發送的通知標識符獨一無二。如果收到相同的 NotificationId 兩次,則視為重複。

  2. EventType (字串):指示通知被觸發的事件類型。

  3. EventTime (字串):事件被觸發的時間戳。 變量載入樣板欄位 提供對網絡呼叫的彈性,其中包括:

  4. EventPayload (對象):包含啟動網狀呼叫的 EventType 特定資訊。EventPayload 模型的結構會根據事件類型而變化。

下面的例子顯示了 刪除請求 事件的付載方案:

刪除請求的示例樣式

{
"NotificationId": "string",
"EventType": "RightToErasureRequest",
"EventTime": "2023-12-30T16:24:24.2118874Z",
"EventPayload": {
"UserId": 1,
"GameIds": [
1234, 2345
]
}
}

處理通知

如果您儲存任何個人識別資訊 (PII)的用戶,例如他們的使用者ID,當使用者提交此類要求來遵守GDPR刪除權要求時,您必須刪除此資訊,以遵守GDPR刪除權要求。如果您在數據儲存中儲存 PII,您可以創建一個機器人來處理網絡通知和幫助自動刪除數據,提供您可以自動刪除數據。見 自動化刪除權限請求刪除示例 以獲得在 Guilded 或 Discord 內創建一個機器人的示例,該機器人使用 開放雲端 API 來刪除個人資訊作為自動化解決方案的數據儲存 的方法。這個例子可以適應處理其他通知,例如訂閱事件。

如果您使用自訂終端點作為網絡服務器而不是第三方工具,您可以從網絡付載中提取將被刪除的數據,並構建自己的自動化解決方案。以下代碼示例是一個防止重播攻擊的伺服器的例子,即通過驗證時戳來防止請求來自 Roblox:

Extracting PII from Payload

const crypto = require('crypto');
const express = require('express');
const secret = '<your_secret>' // This can be set as an environment variable
let app = express();
app.use(express.json());
app.all('/*', function (req, res) {
console.log('New request recieved');
// Extract the timestamp and signature from header
const signatureHeader = req.headers['roblox-signature'].split(',');
const timestamp = signatureHeader.find(e => e.startsWith('t=')).substring(2);
const signature = signatureHeader.find(e => e.startsWith('v1=')).substring(3);
// Ensure the request came within a 300 second window to prevent replay attacks
const requestTimestampMs = timestamp * 1000;
const windowTimeMs = 300 * 1000;
const oldestTimestampAllowed = Date.now() - windowTimeMs;
if (requestTimestampMs < oldestTimestampAllowed) {
return res.status(403).send('Expired Request');
}
// Validate signature
const message = `${timestamp}.${JSON.stringify(req.body)}`;
const hmac = crypto.createHmac('sha256', secret);
const calculatedSignature = hmac.update(message).digest('base64');
if (signature !== calculatedSignature) {
return res.status(401).send('Unauthorized Request');
}
// 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'];
console.log(`Payload data: UserId=${userId} and GameIds=${gameIds}`);
// If you store PII in data stores, use the UserId and GameIds to delete the information from data stores.
}
return res.json({ message: 'Processed the message successfully' });
});
app.listen(8080, function () {
console.log('Server started');
});