监控Slack中的Experience Platform事件

了解如何通过与Experience Platform App Builder webhook代理集成,在Slack中接收Adobe通知。 数据工程师和管理员可能希望在Slack中接收来自Adobe Experience Platform的主动通知,以监控其Platform实施的运行状况。 本教程概述了使用Adobe App Builder将Adobe I/O Events连接到Slack的架构和实施步骤。

为什么是webhook代理?

由于验证过程中的协议不匹配,无法将Adobe I/O Events直接连接到Slack传入Webhook。

  • 挑战:当您使用Adobe I/O Events注册webhook时,Adobe会向您的端点发送“挑战”请求(GETPOST)。 您的端点必须成功处理此质询并返回特定值以确认所有权。

  • 限制: Slack的传入Webhook仅用于摄取JSON负载进行消息传送。 它们没有逻辑来识别或响应Adobe的验证质询握手。

  • 解决方案:使用Adobe App Builder部署中间webhook代理。 此代理位于Adobe和Slack之间,用于:

    1. 截获来自Adobe的请求并响应验证挑战。
    2. 将有效负载格式化为与Slack兼容的消息,并将其转发到Slack。
  • 传递方法:运行时操作。 运行时操作随Adobe App Builder一起打包。 使用运行时操作(非Web操作)作为事件处理程序时,Adobe I/O Events会自动处理签名验证和质询响应。 推荐使用运行时操作,因为此方法需要较少的代码并提供内置安全性。

架构概述

什么是Adobe Developer Console?

Adobe Developer Console是管理Adobe项目、API和凭据的中心门户。 您可以在此处创建项目、配置身份验证和注册Webhook。

什么是App Builder?

Adobe App Builder是一个完整的框架,它允许企业开发人员构建云原生应用程序。

  • 配置:默认情况下不启用App Builder;必须作为功能为您的组织配置它。 确保您的组织具有​ App Builder ​权利。

  • 项目模板: App Builder项目是专门使用​中的 App BuilderDeveloper Console模板创建的(来自模板​ > ​App Builder的项目)。 模板会自动设置必要的工作区和运行时环境。

  • App Builder快速入门指南:请参阅文档以配置并创建您的第一个项目(从模板)。

什么是Adobe I/O Runtime?

Adobe I/O Runtime是支持App Builder的无服务器平台。 它允许开发人员部署响应HTTP请求运行的代码(Functions-as-a-Service),而无需管理服务器基础架构。

在此实现中,我们使用​操作。 Action是在Adobe I/O Runtime上运行的无状态函数(在Node.js中编写)。 我们的操作将用作Adobe I/O Events与之通信的公共HTTP端点。

有关详细信息,请参阅Adobe I/O Runtime文档

实施指南

先决条件

开始之前,请确保您满足以下条件:

  • Adobe Developer Console访问权限:您必须有权访问已启用App Builder的组织中的系统管理员或开发人员角色

    note tip
    TIP
    要验证App Builder配置,请登录Adobe Developer Console,确保您处于所需的组织中,选择​从模板创建项目,并验证App Builder模板是否可用。 如果不是,请查看App Builder常见问题解答部分"如何获取App Builder"
  • Node.js和npm:此项目需要Node.js,其中包括NPM (节点包管理器)。 NPM用于安装Adobe CLI和管理项目依赖项。

  • aio CLI:已通过终端安装: npm install -g @adobe/aio-cli

  • Slack应用程序配置:您需要在工作区中设置Slack应用程序,并激活​传入Webhook

步骤1:在Adobe Developer Console中创建项目

首先,在Adobe Developer Console中使用App Builder模板创建一个项目:

  1. 登录Adobe Developer Console
  2. 选择​从模板创建项目
  3. 选择App Builder模板
  4. 输入项目标题,例如Slack webhook integration
  5. 选择​保存

初始化运行时环境

在终端中运行以下命令以创建项目结构:

登录aio

aio login

步骤2:初始化新的App Builder项目

aio app init slack-webhook-proxy
  1. 选择您的组织并按​Enter

  2. 选择您在上一步中创建的项目(例如,Slack webhook integration),然后按​Enter

  3. 选择​ 仅我的组织支持的模板 ​选项

  4. 按​ Enter ​跳过示例部分

  5. 出现提示时,请确保选择了以下组件(应填充圆圈),然后按​Enter

    1. 操作:部署运行时操作
    2. 事件:发布到Adobe I/O Events
    3. Web Assets:部署到托管的静态资源
  6. 使用“向上”和“向下”箭头,导航传入列表并选择​Adobe Experience Platform:实时客户个人资料,然后按​Enter

  7. 通用​操作是自动生成的

  8. 为UI选择​纯HTML/JS,然后按​Enter

  9. 将​ generic ​保留为示例操作,以展示如何访问外部API名称,并按​Enter

  10. 保留​ publish-events ​作为示例操作名称,以使用云事件格式创建消息,然后按​Enter

应完成应用程序初始化。

导航到项目目录

cd slack-webhook-proxy

添加Web操作

aio app add action
  1. 选择​仅我的组织支持的模板,然后按​Enter
  2. 在呈现的表中查看​ publish-events ​操作;按​ 共享空间 ​选择该操作。 如果名称旁边的圆圈已填充(如视频教程中所示),请按​Enter
  3. 命名操作webhook-proxy

步骤3:更新代理操作代码

在IDE或文本编辑器中,使用以下代码创建/修改文件actions/webhook-proxy/index.js。 此实施会将事件转发到Slack。 使用运行时操作注册时,签名验证和质询处理是自动进行的。

const fetch = require("node-fetch");
const { Core } = require("@adobe/aio-sdk");

/**
 * Adobe I/O Events to Slack Runtime Proxy
 *
 * Receives events from Adobe I/O Events and forwards them to Slack.
 * Signature verification and challenge handling are automatic when
 * using Runtime Action registration (non-web action).
 */
async function main(params) {
  const logger = Core.Logger("webhook-proxy", { level: params.LOG_LEVEL || "info" });

  try {
    logger.info(`Event received: ${JSON.stringify(params)}`);

    // Forward to Slack
    return forwardToSlack(params, params.SLACK_WEBHOOK_URL, logger);

  } catch (error) {
    logger.error(`Error: ${error.message}`);
    return { statusCode: 500, body: { error: "Internal server error" } };
  }
}

/**
 * Forwards the event payload to Slack
 */
async function forwardToSlack(payload, webhookUrl, logger) {
  if (!webhookUrl) {
    logger.error("SLACK_WEBHOOK_URL not configured");
    return { statusCode: 500, body: { error: "Server configuration error" } };
  }

  // Extract Adobe headers passed to runtime action
  const headers = {
    "x-adobe-event-code": payload["x-adobe-event-code"],
    "x-adobe-event-id": payload["x-adobe-event-id"],
    "x-adobe-provider": payload["x-adobe-provider"]
  };

  const slackMessage = buildSlackMessage(payload, headers);

  const response = await fetch(webhookUrl, {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify(slackMessage)
  });

  if (!response.ok) {
    const errorText = await response.text();
    logger.error(`Slack API error: ${response.status} - ${errorText}`);
    return { statusCode: response.status, body: { error: errorText } };
  }

  logger.info("Event forwarded to Slack");
  return { statusCode: 200, body: { success: true } };
}

/**
 * Builds a Slack Block Kit message from the event payload
 */
function buildSlackMessage(payload, headers) {
  // Adobe passes event code as x-adobe-event-code header (available in params for runtime actions)
  const eventType = headers["x-adobe-event-code"] ||
                    payload["x-adobe-event-code"] ||
                    payload.event_code ||
                    payload.type ||
                    payload.event_type ||
                    "Adobe Event";
  const eventId = headers["x-adobe-event-id"] || payload["x-adobe-event-id"] || payload.event_id || payload.id || "N/A";
  const eventData = payload.data || payload.event || payload;

  return {
    blocks: [
      {
        type: "header",
        text: { type: "plain_text", text: `Event: ${eventType}`, emoji: true }
      },
      {
        type: "section",
        fields: formatDataFields(eventData)
      },
      { type: "divider" },
      {
        type: "context",
        elements: [{
          type: "mrkdwn",
          text: `*Event ID:* ${eventId}  |  *Time:* ${new Date().toISOString()}`
        }]
      }
    ]
  };
}

/**
 * Formats event data as Slack mrkdwn fields
 */
function formatDataFields(data, maxFields = 10) {
  if (typeof data !== "object" || data === null) {
    return [{ type: "mrkdwn", text: `*Payload:*\n${String(data)}` }];
  }

  const entries = Object.entries(data);
  if (entries.length === 0) {
    return [{ type: "mrkdwn", text: "_No data provided_" }];
  }

  return entries.slice(0, maxFields).map(([key, value]) => ({
    type: "mrkdwn",
    text: `*${key}:*\n${typeof value === "object" ? `\`\`\`${JSON.stringify(value)}\`\`\`` : value}`
  }));
}

exports.main = main;

步骤4:配置操作

app.config.yaml中的操作配置是关键的。 使用Web:否,创建可在Developer Console中注册为运行时操作的非Web操作。

application:
  runtimeManifest:
    packages:
      slack-webhook-proxy:
        license: Apache-2.0
        actions:
          webhook-proxy:
            function: actions/webhook-proxy/index.js
            web: no
            runtime: nodejs:22
            inputs:
              LOG_LEVEL: info
              SLACK_WEBHOOK_URL: $SLACK_WEBHOOK_URL
            annotations:
              require-adobe-auth: false
              final: true

为什么web: no?

当您使用非Web操作并通过Developer Console中的“运行时操作”选项注册它时,Adobe I/O Events会自动执行以下操作:

  • 处理质询验证(GETPOST
  • 在调用操作之前验证数字签名
  • 将签名验证器操作链接到操作之前

这意味着您的代码只需要处理业务逻辑(转发到Slack)。

步骤4:更新环境变量

为了安全地管理凭据,我们使用环境变量。 在项目的根目录中创建/修改.env文件以添加Slack webhook URL。 如果未看到.env文件,请确保在系统上显示隐藏的文件:

# ... other .env file content ...

SLACK_WEBHOOK_URL=https://hooks.slack.com/services/YOUR/WEBHOOK/URL

步骤5:部署操作

设置环境变量后,部署操作。 在终端中运行此命令时,请确保位于项目的根目录下,即slack-webhook-proxy

aio app deploy

您的操作将部署到Adobe I/O Runtime,并且可在Developer Console中注册操作。

步骤6:在Adobe Developer Console中注册操作

现在您的操作已部署,请将其注册为Adobe事件的目标。

  1. 导航到Adobe Developer Console并打开您的App Builder项目。

  2. 选择您的​Workspace

  3. 选择​ 添加服务 ​并选择​事件

  4. 选择​ Adobe Experience Platform ​作为产品。

  5. 选择​ 平台通知 ​作为事件类型。

  6. 选择您希望在Slack中收到通知的特定事件(或所有事件),然后选择​下一步

  7. 选择或创建您的OAuth凭据

  8. 配置​事件注册详细信息

    1. 注册名称:为注册提供一个描述性名称。
    2. 注册描述:确保此描述是显式的,以便其他参与者能够了解其用途。
    3. 选择​下一步
    4. 交付方法:选择​运行时操作(不是“Webhook”)。
    5. 运行时操作:从下拉列表中选择webhook-proxy(如果未看到该页面,请刷新该页面)。
  9. 选择​保存配置的事件

步骤7:使用示例事件进行验证

您可以通过单击任何已配置事件旁边的“发送示例事件”图标,端到端地测试整个流。

示例事件通过您在创建Slack应用程序并创建webhook时配置的渠道发送;您应该看到类似以下的内容:

Slack中的监视事件示例

恭喜,您已成功地将Slack与Experience Platform活动集成!

常见问题

以下是配置代理时可能会遇到的一些问题以及解决这些问题的一些可能方法。

  • 无法查看IMS组织:如果在运行aio app init时未看到您的IMS组织列表,请尝试以下操作。 在终端中运行aio logout,在默认Web浏览器上注销Experience Cloud,然后再次运行aio login
  • 操作未出现在下拉列表​中:确保在web: no中设置了app.config.yaml。 运行时操作下拉列表中只显示非Web操作。 部署后刷新“Developer Console”页面。
  • 签名验证失败:如果在激活日志中看到此信息,则表示Adobe的内置验证器拒绝了请求。 对于合法的Adobe事件,不应发生这种情况。 检查事件注册是否正确配置。
  • Slack未接收消息:检查SLACK_WEBHOOK_URL文件中是否正确设置了.env,以及Slack应用是否启用了传入Webhook。
  • 操作超时:运行时操作的超时为60秒。 如果您的操作需要较长时间,请考虑改用日志记录方法。
recommendation-more-help
9051d869-e959-46c8-8c52-f0759cee3763