預覽 Google Chat 訊息中的連結

為避免使用者在 Google Chat 中分享連結時切換情境,Chat 應用程式可透過在訊息中附加資訊卡預覽連結,提供更多資訊,並讓使用者直接在 Google Chat 中採取行動。

在 Google Chat 中,使用者會看到附加元件以 Google Chat 應用程式的形式顯示。詳情請參閱「擴充 Google Chat 總覽」。

舉例來說,假設有一個 Google Chat 聊天室,其中包含公司內所有客戶服務專員,以及名為 Case-y 的 Chat 應用程式。客服專員經常在 Chat 聊天室中分享客戶服務案件的連結,每次分享後,同事都必須開啟案件連結,查看指派者、狀態和主旨等詳細資料。同樣地,如果有人想接手案件或變更狀態,就必須開啟連結。

連結預覽功能可讓專案空間的 Chat 應用程式 Case-y 在有人分享案件連結時,附加顯示指派者、狀態和主題的資訊卡。資訊卡上的按鈕可讓服務專員接手案件,並直接在聊天串流中變更狀態。

當使用者在訊息中加入連結時,系統會顯示一個方塊,讓使用者知道 Chat 應用程式可能會預覽該連結。

用來表示 Chat 應用程式可能會預覽連結的方塊

傳送訊息後,連結會傳送至 Chat 應用程式,然後系統會產生資訊卡並附加至使用者的訊息。

Chat 應用程式透過在訊息中附加資訊卡來預覽連結

除了連結之外,資訊卡還會提供連結的其他資訊,包括按鈕等互動元素。Chat 應用程式可根據使用者互動 (例如按鈕點選) 更新附加的資訊卡。

如果使用者不希望 Chat 應用程式透過在訊息中附加資訊卡來預覽連結,可以按一下預覽方塊中的 來避免預覽。使用者隨時可以點選「Remove preview」,移除所附資訊卡。

必要條件

Node.js

可擴充 Google Chat 功能的 Google Workspace 外掛程式。如要建構一個,請完成HTTP 快速入門

Apps Script

可擴充 Google Chat 功能的 Google Workspace 外掛程式。如要建構一個應用程式,請完成 Apps Script 快速入門

在 Google Cloud 控制台的 Chat 應用程式設定頁面中,將特定連結 (例如 example.comsupport.example.comsupport.example.com/cases/) 註冊為網址模式,讓 Chat 應用程式能夠預覽這些連結。

連結預覽設定選單

  1. 開啟 Google Cloud 控制台
  2. 按一下「Google Cloud」旁邊的向下箭頭 ,然後開啟 Chat 應用程式的專案。
  3. 在搜尋欄位中輸入 Google Chat API,然後點選「Google Chat API」
  4. 依序點選「管理」>「設定」
  5. 在「連結預覽」下方,新增或編輯網址模式。
    1. 如要為新網址模式設定連結預覽,請按一下「新增網址模式」
    2. 如要編輯現有網址模式的設定,請按一下向下箭頭
  6. 在「主機模式」欄位中,輸入網址模式的網域。Chat 應用程式會預覽這個網域的連結。

    如要讓 Chat 應用程式預覽特定子網域 (例如 subdomain.example.com) 的連結,請加入該子網域。

    如要讓 Chat 應用程式預覽整個網域的連結,請指定以星號 (*) 做為子網域的萬用字元。舉例來說,*.example.com 符合 subdomain.example.comany.number.of.subdomains.example.com

  7. 在「Path prefix」欄位中輸入要附加至主機模式網域的路徑。

    如要比對主機模式網域中的所有網址,請將「Path prefix」留空。

    舉例來說,如果主機模式為 support.example.com,如要比對主機模式為 support.example.com/cases/ 的個案網址,請輸入 cases/

  8. 按一下 [完成]。

  9. 按一下 [儲存]

從現在起,只要有人在 Chat 聊天室中加入與連結預覽網址模式相符的連結,應用程式就會在該聊天室中預覽連結。

為特定連結設定連結預覽功能後,Chat 應用程式就能透過附加更多資訊來辨識及預覽連結。

在包含 Chat 應用程式的 Chat 聊天室中,如果某人的訊息含有與連結預覽網址模式相符的連結,Chat 應用程式會透過 MessagePayload 接收事件物件。在酬載中,message.matchedUrl 物件包含使用者在訊息中加入的連結:

JSON

message: {
  matchedUrl: {
    url: "https://support.example.com/cases/case123"
  },
  ... // other message attributes redacted
}

只要檢查 MESSAGE 事件酬載中是否有 matchedUrl 欄位,Chat 應用程式就能在訊息中加入預覽連結的資訊。Chat 應用程式可以回覆基本文字訊息,或附加資訊卡。

以簡訊回覆

對於基本回應,Chat 應用程式可以透過以文字訊息回覆連結來預覽連結。這個範例會附加訊息,重複符合連結預覽網址模式的連結網址。

Node.js

/**
 * Google Cloud Function that handles messages that have links whose
 * URLs match URL patterns configured for link previewing.
 *
 *
 * @param {Object} req Request sent from Google Chat space
 * @param {Object} res Response to send back
 */
exports.previewLinks = function previewLinks(req, res) {
  const chatEvent = req.body.chat;

  // Handle MESSAGE events
  if(chatEvent.messagePayload) {
    return res.send(handlePreviewLink(chatEvent.messagePayload.message));
  // Handle button clicks
  } else if(chatEvent.buttonClickedPayload) {
    return res.send(handleCardClick(chatEvent.buttonClickedPayload.message));
  }
};

/**
 * Respond to messages that have links whose URLs match URL patterns configured
 * for link previewing.
 *
 * @param {Object} chatMessage The chat message object from Google Workspace Add On event.
 * @return {Object} Response to send back depending on the matched URL.
 */
function handlePreviewLink(chatMessage) {
  // If the Chat app does not detect a link preview URL pattern, reply
  // with a text message that says so.
  if (!chatMessage.matchedUrl) {
    return { hostAppDataAction: { chatDataAction: { createMessageAction: { message: {
      text: 'No matchedUrl detected.'
    }}}}};
  }

  // Reply with a text message for URLs of the subdomain "text"
  if (chatMessage.matchedUrl.url.includes("text.example.com")) {
    return { hostAppDataAction: { chatDataAction: { createMessageAction: { message: {
      text: 'event.chat.messagePayload.message.matchedUrl.url: ' + chatMessage.matchedUrl.url
    }}}}};
  }
}

Apps Script

/**
 * Reply to messages that have links whose URLs match the pattern
 * "text.example.com" configured for link previewing.
 *
 * @param {Object} event The event object from Google Workspace Add-on.
 *
 * @return {Object} The action response.
 */
function onMessage(event) {
  // Stores the Google Chat event as a variable.
  const chatMessage = event.chat.messagePayload.message;

  // If the Chat app doesn't detect a link preview URL pattern, reply
  // with a text message that says so.
  if (!chatMessage.matchedUrl) {
    return { hostAppDataAction: { chatDataAction: { createMessageAction: { message: {
      text: 'No matchedUrl detected.'
    }}}}};
  }

  // Reply with a text message for URLs of the subdomain "text".
  if (chatMessage.matchedUrl.url.includes("text.example.com")) {
    return { hostAppDataAction: { chatDataAction: { createMessageAction: { message: {
      text: 'event.chat.messagePayload.message.matchedUrl.url: ' + chatMessage.matchedUrl.url
    }}}}};
  }
}

如要將資訊卡附加至預覽連結,請使用 UpdateInlinePreviewAction 類型的 ChatDataActionMarkup 物件,回傳動作 DataActions

在以下範例中,Chat 應用程式會在包含網址模式 support.example.com 的訊息中加入預覽資訊卡。

Chat 應用程式透過在訊息中附加資訊卡來預覽連結

Node.js

/**
 * Google Cloud Function that handles messages that have links whose
 * URLs match URL patterns configured for link previewing.
 *
 *
 * @param {Object} req Request sent from Google Chat space
 * @param {Object} res Response to send back
 */
exports.previewLinks = function previewLinks(req, res) {
  const chatEvent = req.body.chat;

  // Handle MESSAGE events
  if(chatEvent.messagePayload) {
    return res.send(handlePreviewLink(chatEvent.messagePayload.message));
  // Handle button clicks
  } else if(chatEvent.buttonClickedPayload) {
    return res.send(handleCardClick(chatEvent.buttonClickedPayload.message));
  }
};

/**
 * Respond to messages that have links whose URLs match URL patterns configured
 * for link previewing.
 *
 * @param {Object} chatMessage The chat message object from Google Workspace Add On event.
 * @return {Object} Response to send back depending on the matched URL.
 */
function handlePreviewLink(chatMessage) {
  // Attach a card to the message for URLs of the subdomain "support"
  if (chatMessage.matchedUrl.url.includes("support.example.com")) {
    // A hard-coded card is used in this example. In a real-life scenario,
    // the case information would be fetched and used to build the card.
    return { hostAppDataAction: { chatDataAction: { updateInlinePreviewAction: { cardsV2: [{
      cardId: 'attachCard',
      card: {
        header: {
          title: 'Example Customer Service Case',
          subtitle: 'Case basics',
        },
        sections: [{ widgets: [
        { decoratedText: { topLabel: 'Case ID', text: 'case123'}},
        { decoratedText: { topLabel: 'Assignee', text: 'Charlie'}},
        { decoratedText: { topLabel: 'Status', text: 'Open'}},
        { decoratedText: { topLabel: 'Subject', text: 'It won\'t turn on...' }},
        { buttonList: { buttons: [{
          text: 'OPEN CASE',
          onClick: { openLink: {
            url: 'https://support.example.com/orders/case123'
          }},
        }, {
          text: 'RESOLVE CASE',
          onClick: { openLink: {
            url: 'https://support.example.com/orders/case123?resolved=y',
          }},
        }, {
          text: 'ASSIGN TO ME',
          // Use runtime environment variable set with self URL
          onClick: { action: { function: process.env.BASE_URL }}
        }]}}
        ]}]
      }
    }]}}}};
  }
}

Apps Script

這個範例會傳回 卡片 JSON,藉此傳送資訊卡訊息。您也可以使用 Apps Script 卡片服務

/**
 * Attach a card to messages that have links whose URLs match the pattern
 * "support.example.com" configured for link previewing.
 *
 * @param {Object} event The event object from Google Workspace Add-on.
 *
 * @return {Object} The action response.
 */
function onMessage(event) {
  // Stores the Google Chat event as a variable.
  const chatMessage = event.chat.messagePayload.message;

  // Attach a card to the message for URLs of the subdomain "support".
  if (chatMessage.matchedUrl.url.includes("support.example.com")) {
    // A hard-coded card is used in this example. In a real-life scenario,
    // the case information would be fetched and used to build the card.
    return { hostAppDataAction: { chatDataAction: { updateInlinePreviewAction: { cardsV2: [{
      cardId: 'attachCard',
      card: {
        header: {
          title: 'Example Customer Service Case',
          subtitle: 'Case summary',
        },
        sections: [{ widgets: [
        { decoratedText: { topLabel: 'Case ID', text: 'case123'}},
        { decoratedText: { topLabel: 'Assignee', text: 'Charlie'}},
        { decoratedText: { topLabel: 'Status', text: 'Open'}},
        { decoratedText: { topLabel: 'Subject', text: 'It won\'t turn on...' }},
        { buttonList: { buttons: [{
          text: 'OPEN CASE',
          onClick: { openLink: {
            url: 'https://support.example.com/orders/case123'
          }},
        }, {
          text: 'RESOLVE CASE',
          onClick: { openLink: {
            url: 'https://support.example.com/orders/case123?resolved=y',
          }},
        }, {
          text: 'ASSIGN TO ME',
          // Clicking this button triggers the execution of the function
          // "assign" from the Apps Script project.
          onClick: { action: { function: 'assign'}}
        }]}}
        ]}]
      }
    }]}}}};
  }
}

當使用者與連結預覽資訊卡互動 (例如點選資訊卡上的按鈕) 時,Chat 應用程式可以更新該資訊卡。

如要更新資訊卡,Chat 應用程式必須使用下列任一 ChatDataActionMarkup 物件,傳回 DataActions 動作:

如要判斷訊息的傳送者,請使用事件酬載 (buttonClickedPayload) 檢查傳送者 (message.sender.type) 是否設為 HUMAN (使用者) 或 BOT (Chat 應用程式)。

以下範例說明如何在使用者點選「指派給我」按鈕時,透過更新資訊卡的「指派者」欄位並停用按鈕,讓 Chat 應用程式更新連結預覽畫面。

即時通訊應用程式預覽連結,連結中附有附加至訊息的更新版資訊卡

Node.js

/**
 * Google Cloud Function that handles messages that have links whose
 * URLs match URL patterns configured for link previewing.
 *
 *
 * @param {Object} req Request sent from Google Chat space
 * @param {Object} res Response to send back
 */
exports.previewLinks = function previewLinks(req, res) {
  const chatEvent = req.body.chat;

  // Handle MESSAGE events
  if(chatEvent.messagePayload) {
    return res.send(handlePreviewLink(chatEvent.messagePayload.message));
  // Handle button clicks
  } else if(chatEvent.buttonClickedPayload) {
    return res.send(handleCardClick(chatEvent.buttonClickedPayload.message));
  }
};

/**
 * Respond to clicks by assigning user and updating the card that was attached to a
 * message with a previewed link.
 *
 * @param {Object} chatMessage The chat message object from Google Workspace Add On event.
 * @return {Object} Action response depending on the original message.
 */
function handleCardClick(chatMessage) {
  // Creates the updated card that displays "You" for the assignee
  // and that disables the button.
  //
  // A hard-coded card is used in this example. In a real-life scenario,
  // an actual assign action would be performed before building the card.
  const message = { cardsV2: [{
    cardId: 'attachCard',
    card: {
      header: {
        title: 'Example Customer Service Case',
        subtitle: 'Case basics',
      },
      sections: [{ widgets: [
        { decoratedText: { topLabel: 'Case ID', text: 'case123'}},
        // The assignee is now "You"
        { decoratedText: { topLabel: 'Assignee', text: 'You'}},
        { decoratedText: { topLabel: 'Status', text: 'Open'}},
        { decoratedText: { topLabel: 'Subject', text: 'It won\'t turn on...' }},
        { buttonList: { buttons: [{
          text: 'OPEN CASE',
          onClick: { openLink: {
            url: 'https://support.example.com/orders/case123'
          }},
        }, {
          text: 'RESOLVE CASE',
          onClick: { openLink: {
            url: 'https://support.example.com/orders/case123?resolved=y',
          }},
        }, {
          text: 'ASSIGN TO ME',
          // The button is now disabled
          disabled: true,
          // Use runtime environment variable set with self URL
          onClick: { action: { function: process.env.BASE_URL }}
        }]}}
      ]}]
    }
  }]};

  // Checks whether the message event originated from a human or a Chat app
  // to return the adequate action response.
  if(chatMessage.sender.type === 'HUMAN') {
    return { hostAppDataAction: { chatDataAction: { updateInlinePreviewAction: message }}};
  } else {
    return { hostAppDataAction: { chatDataAction: { updateMessageAction: message }}};
  }
}

Apps Script

這個範例會傳回 卡片 JSON,藉此傳送資訊卡訊息。您也可以使用 Apps Script 卡片服務

/**
 * Assigns and updates the card that's attached to a message with a
 * previewed link of the pattern "support.example.com".
 *
 * @param {Object} event The event object from the Google Workspace Add-on.
 *
 * @return {Object} Action response depending on the message author.
 */
function assign(event) {
  // Creates the updated card that displays "You" for the assignee
  // and that disables the button.
  //
  // A hard-coded card is used in this example. In a real-life scenario,
  // an actual assign action would be performed before building the card.
  const message = { cardsV2: [{
    cardId: 'attachCard',
    card: {
      header: {
        title: 'Example Customer Service Case',
        subtitle: 'Case summary',
      },
      sections: [{ widgets: [
        { decoratedText: { topLabel: 'Case ID', text: 'case123'}},
        // The assignee is now "You"
        { decoratedText: { topLabel: 'Assignee', text: 'You'}},
        { decoratedText: { topLabel: 'Status', text: 'Open'}},
        { decoratedText: { topLabel: 'Subject', text: 'It won\'t turn on...' }},
        { buttonList: { buttons: [{
          text: 'OPEN CASE',
          onClick: { openLink: {
            url: 'https://support.example.com/orders/case123'
          }},
        }, {
          text: 'RESOLVE CASE',
          onClick: { openLink: {
            url: 'https://support.example.com/orders/case123?resolved=y',
          }},
        }, {
          text: 'ASSIGN TO ME',
          // The button is now disabled
          disabled: true,
          onClick: { action: { function: 'assign'}}
        }]}}
      ]}]
    }
  }]};

  // Use the adequate action response type. It depends on whether the message
  // the preview link card is attached to was created by a human or a Chat app.
  if(event.chat.buttonClickedPayload.message.sender.type === 'HUMAN') {
    return { hostAppDataAction: { chatDataAction: { updateInlinePreviewAction: message }}};
  } else {
    return { hostAppDataAction: { chatDataAction: { updateMessageAction: message }}};
  }
}

限制和注意事項

設定 Chat 應用程式的連結預覽時,請注意下列限制和注意事項:

  • 每個 Chat 應用程式最多可支援 5 個網址模式的連結預覽。
  • Chat 應用程式會為每則訊息預覽一個連結。如果單一訊息中有多個可預覽的連結,系統只會預覽第一個可預覽的連結。
  • 即時通訊應用程式只會預覽以 https:// 開頭的連結,因此 https://support.example.com/cases/ 會預覽,但 support.example.com/cases/ 不會。
  • 除非訊息包含要傳送至 Chat 應用程式的其他資訊 (例如 斜線指令),否則只有連結網址會透過連結預覽傳送至 Chat 應用程式。
  • 如果使用者發布連結,Chat 應用程式只能在使用者與資訊卡互動時 (例如按下按鈕) 更新連結預覽資訊卡。您無法在 Message 資源上呼叫 Chat API 的 update() 方法,以非同步方式更新使用者的訊息。
  • 即時通訊應用程式必須為聊天室中的所有成員預覽連結,因此訊息必須省略 privateMessageViewer 欄位。

在實作連結預覽時,您可能需要讀取應用程式記錄來偵錯 Chat 應用程式。如要讀取記錄檔,請前往 Google Cloud 控制台的「Logs Explorer」(記錄檔探索工具)