將 Google Chat 應用程式建構為 Webhook

本頁說明如何設定 Webhook,透過外部觸發條件將非同步訊息傳送至 Chat 空間。舉例來說,您可以設定監控應用程式,在伺服器當機時透過 Chat 通知待命人員。如要使用 Google Chat 應用程式傳送同步訊息,請參閱「傳送訊息」。

採用這類架構設計時,使用者無法與 Webhook 或已連結的外部應用程式互動,因為通訊是單向的。Webhook 無法進行對話。 無法回應或接收使用者訊息或 Chat 應用程式互動事件。如要回覆訊息,請建構 Chat 應用程式,而非 Webhook。

從技術上來說,Webhook 並非 Chat 應用程式 (Webhook 會使用標準 HTTP 要求連結應用程式),但為了簡化說明,本頁面會將其視為 Chat 應用程式。每個 Webhook 只能在註冊的 Chat 聊天室中使用。傳入 Webhook 可在即時訊息中使用,但前提是所有使用者都啟用 Chat 應用程式。您無法將 Webhook 發布至 Google Workspace Marketplace。

下圖顯示連結至 Chat 的 Webhook 架構:

傳入 Webhook 架構,可將非同步訊息傳送至 Chat。

在上圖中,Chat 應用程式的資訊流程如下:

  1. Chat 應用程式邏輯會接收來自外部第三方服務的資訊,例如專案管理系統或票證工具。
  2. Chat 應用程式邏輯會託管在雲端或地端系統中,這類系統可使用 Webhook 網址,將訊息傳送至特定 Chat 聊天室。
  3. 使用者可以在該特定 Chat 聊天室中接收 Chat 應用程式傳送的訊息,但無法與 Chat 應用程式互動。

必要條件

Python

  • 具有 Google Chat 存取權的 Business 或 Enterprise 版 Google Workspace 帳戶。 Google Workspace 機構必須允許使用者新增及使用連入的 Webhook
  • Python 3.6 以上版本
  • pip 套件管理工具
  • httplib2 程式庫。如要安裝程式庫,請在指令列介面中執行下列指令:

    pip install httplib2
  • Google Chat 聊天室。如要使用 Google Chat API 建立聊天室,請參閱「建立聊天室」。如要在 Chat 中建立群組,請參閱說明中心文件

Node.js

Java

Apps Script

建立 Webhook

如要建立 Webhook,請在要接收訊息的 Chat 聊天室中註冊,然後編寫傳送訊息的指令碼。

註冊傳入 Webhook

  1. 在瀏覽器中開啟 Chat。你無法透過 Chat 行動應用程式設定 Webhook。
  2. 前往要新增 Webhook 的聊天室。
  3. 按一下聊天室名稱旁邊的「展開更多」箭頭 ,然後點選「應用程式和整合」
  4. 按一下「新增 Webhook」

  5. 在「Name」(名稱) 欄位中輸入 Quickstart Webhook

  6. 在「Avatar URL」(大頭貼網址) 欄位中,輸入 https://developers.google.com/chat/images/chat-product-icon.png

  7. 按一下 [儲存]

  8. 如要複製 Webhook 網址,請依序點選「更多」和「複製連結」

編寫 Webhook 指令碼

範例 Webhook 指令碼會將 POST 要求傳送至 Webhook 網址,藉此將訊息傳送至註冊 Webhook 的即時通訊空間。Chat API 會傳回 Message 的例項。

選取一種語言,瞭解如何建立 Webhook 指令碼:

Python

  1. 在工作目錄中,建立名為 quickstart.py 的檔案。

  2. quickstart.py 中貼上下列程式碼:

    python/webhook/quickstart.py
    from json import dumps
    from httplib2 import Http
    
    # Copy the webhook URL from the Chat space where the webhook is registered.
    # The values for SPACE_ID, KEY, and TOKEN are set by Chat, and are included
    # when you copy the webhook URL.
    
    def main():
        """Google Chat incoming webhook quickstart."""
        url = "https://chat.googleapis.com/v1/spaces/SPACE_ID/messages?key=KEY&token=TOKEN"
        app_message = {"text": "Hello from a Python script!"}
        message_headers = {"Content-Type": "application/json; charset=UTF-8"}
        http_obj = Http()
        response = http_obj.request(
            uri=url,
            method="POST",
            headers=message_headers,
            body=dumps(app_message),
        )
        print(response)
    
    
    if __name__ == "__main__":
        main()
  3. url 變數的值替換為您註冊 Webhook 時複製的 Webhook 網址。

Node.js

  1. 在工作目錄中,建立名為 index.js 的檔案。

  2. index.js 中貼上下列程式碼:

    node/webhook/index.js
    /**
     * Sends asynchronous message to Google Chat
     * @return {Object} response
     */
    async function webhook() {
      const url = "https://chat.googleapis.com/v1/spaces/SPACE_ID/messages"
      const res = await fetch(url, {
        method: "POST",
        headers: {"Content-Type": "application/json; charset=UTF-8"},
        body: JSON.stringify({text: "Hello from a Node script!"})
      });
      return await res.json();
    }
    
    webhook().then(res => console.log(res));
  3. url 變數的值替換為您註冊 Webhook 時複製的 Webhook 網址。

Java

  1. 在工作目錄中,建立名為 pom.xml 的檔案。

  2. pom.xml 中,複製並貼上下列內容:

    java/webhook/pom.xml
    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
      <modelVersion>4.0.0</modelVersion>
    
      <groupId>com.google.chat.webhook</groupId>
      <artifactId>java-webhook-app</artifactId>
      <version>0.1.0</version>
    
      <name>java-webhook-app</name>
      <url>https://github.com/googleworkspace/google-chat-samples/tree/main/java/webhook</url>
    
      <properties>
        <maven.compiler.target>11</maven.compiler.target>
        <maven.compiler.source>11</maven.compiler.source>
      </properties>
    
      <dependencies>
        <dependency>
            <groupId>com.google.code.gson</groupId>
            <artifactId>gson</artifactId>
            <version>2.9.1</version>
        </dependency>
      </dependencies>
    
      <build>
        <pluginManagement>
          <plugins>
            <plugin>
              <artifactId>maven-compiler-plugin</artifactId>
              <version>3.8.0</version>
            </plugin>
          </plugins>
        </pluginManagement>
      </build>
    </project>
  3. 在工作目錄中,建立下列目錄結構 src/main/java

  4. src/main/java 目錄中,建立名為 App.java 的檔案。

  5. App.java 中貼上下列程式碼:

    java/webhook/src/main/java/com/google/chat/webhook/App.java
    import com.google.gson.Gson;
    import java.net.http.HttpClient;
    import java.net.http.HttpRequest;
    import java.net.http.HttpResponse;
    import java.util.Map;
    import java.net.URI;
    
    public class App {
      private static final String URL = "https://chat.googleapis.com/v1/spaces/AAAAGCYeSRY/messages";
      private static final Gson gson = new Gson();
      private static final HttpClient client = HttpClient.newHttpClient();
    
      public static void main(String[] args) throws Exception {
        String message = gson.toJson(Map.of("text", "Hello from Java!"));
    
        HttpRequest request = HttpRequest.newBuilder(URI.create(URL))
          .header("accept", "application/json; charset=UTF-8")
          .POST(HttpRequest.BodyPublishers.ofString(message)).build();
    
        HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
    
        System.out.println(response.body());
      }
    }
  6. URL 變數的值替換為您註冊網路鉤子時複製的網路鉤子網址。

Apps Script

  1. 在瀏覽器中前往 Apps Script

  2. 按一下「New Project」

  3. 貼上下列程式碼:

    apps-script/webhook/webhook.gs
    function webhook() {
      const url = "https://chat.googleapis.com/v1/spaces/SPACE_ID/messages"
      const options = {
        "method": "post",
        "headers": {"Content-Type": "application/json; charset=UTF-8"},
        "payload": JSON.stringify({"text": "Hello from Apps Script!"})
      };
      const response = UrlFetchApp.fetch(url, options);
      console.log(response);
    }
  4. url 變數的值替換為您註冊網路鉤子時複製的網路鉤子網址。

執行 Webhook 指令碼

在 CLI 中執行指令碼:

Python

  python3 quickstart.py

Node.js

  node index.js

Java

  mvn compile exec:java -Dexec.mainClass=App

Apps Script

  • 按一下「執行」

執行程式碼時,Webhook 會將訊息傳送至您註冊的聊天室。

發起或回覆訊息討論串

  1. 在訊息要求主體中指定 spaces.messages.thread.threadKey。視您是要發起還是回覆討論串,請為 threadKey 使用下列值:

    • 如要啟動討論串,請將 threadKey 設為任意字串,但請記下這個值,以便回覆討論串。

    • 如要回覆討論串,請指定討論串開始時設定的 threadKey。舉例來說,如要回覆使用 MY-THREAD 的初始訊息,請設定 MY-THREAD

  2. 如果找不到指定的 threadKey,請定義執行緒行為:

    • 回覆討論串或發起新討論串。在 Webhook 網址中加入 messageReplyOption=REPLY_MESSAGE_FALLBACK_TO_NEW_THREAD 參數。傳遞這個網址參數會導致 Chat 使用指定的 threadKey 尋找現有討論串。如果找到相符的討論串,系統就會將訊息發布為該討論串的回覆。如果沒有,郵件會啟動對應的threadKey新討論串。

    • 回覆討論串或不採取任何行動。在 Webhook 網址中加入 messageReplyOption=REPLY_MESSAGE_OR_FAIL 參數。傳遞這個網址參數會導致 Chat 使用指定的 threadKey 尋找現有討論串。如果找到相符的討論串,系統就會將訊息發布為該討論串的回覆。如果找不到任何收件者,系統就不會傳送訊息。

    詳情請參閱 messageReplyOption

下列程式碼範例會啟動或回覆訊息討論串:

Python

python/webhook/thread-reply.py
from json import dumps
from httplib2 import Http

# Copy the webhook URL from the Chat space where the webhook is registered.
# The values for SPACE_ID, KEY, and TOKEN are set by Chat, and are included
# when you copy the webhook URL.
#
# Then, append messageReplyOption=REPLY_MESSAGE_FALLBACK_TO_NEW_THREAD to the
# webhook URL.


def main():
    """Google Chat incoming webhook that starts or replies to a message thread."""
    url = "https://chat.googleapis.com/v1/spaces/SPACE_ID/messages?key=KEY&token=TOKEN&messageReplyOption=REPLY_MESSAGE_FALLBACK_TO_NEW_THREAD"
    app_message = {
        "text": "Hello from a Python script!",
        # To start a thread, set threadKey to an arbitratry string.
        # To reply to a thread, specify that thread's threadKey value.
        "thread": {"threadKey": "THREAD_KEY_VALUE"},
    }
    message_headers = {"Content-Type": "application/json; charset=UTF-8"}
    http_obj = Http()
    response = http_obj.request(
        uri=url,
        method="POST",
        headers=message_headers,
        body=dumps(app_message),
    )
    print(response)


if __name__ == "__main__":
    main()

Node.js

node/webhook/thread-reply.js
/**
 * Sends asynchronous message to Google Chat
 * @return {Object} response
 */
async function webhook() {
  const url = "https://chat.googleapis.com/v1/spaces/SPACE_ID/messages?key=KEY&token=TOKEN&messageReplyOption=REPLY_MESSAGE_FALLBACK_TO_NEW_THREAD"
  const res = await fetch(url, {
    method: "POST",
    headers: {"Content-Type": "application/json; charset=UTF-8"},
    body: JSON.stringify({
      text: "Hello from a Node script!",
      thread: {threadKey: "THREAD_KEY_VALUE"}
    })
  });
  return await res.json();
}

webhook().then(res => console.log(res));

Apps Script

apps-script/webhook/thread-reply.gs
function webhook() {
  const url = "https://chat.googleapis.com/v1/spaces/SPACE_ID/messages?key=KEY&token=TOKEN&messageReplyOption=REPLY_MESSAGE_FALLBACK_TO_NEW_THREAD"
  const options = {
    "method": "post",
    "headers": {"Content-Type": "application/json; charset=UTF-8"},
    "payload": JSON.stringify({
      "text": "Hello from Apps Script!",
      "thread": {"threadKey": "THREAD_KEY_VALUE"}
    })
  };
  const response = UrlFetchApp.fetch(url, options);
  console.log(response);
}

處理錯誤

Webhook 要求可能會因為各種原因而失敗,包括:

  • 無效的要求。
  • Webhook 或代管該 Webhook 的聊天室已刪除。
  • 間歇性問題,例如網路連線或配額限制。

建構 Webhook 時,請透過下列方式妥善處理錯誤:

  • 記錄失敗情形。
  • 如果是時間、配額或網路連線錯誤,請以指數輪詢方式重試要求
  • 不採取任何行動,如果傳送 Webhook 訊息並不重要,這是適當的做法。

Google Chat API 會以 google.rpc.Status 形式傳回錯誤,其中包含 HTTP 錯誤 code,指出發生的錯誤類型:用戶端錯誤 (400 系列) 或伺服器錯誤 (500 系列)。如要查看所有 HTTP 對應,請參閱google.rpc.Code

{
    "code": 503,
    "message": "The service is currently unavailable.",
    "status": "UNAVAILABLE"
}

如要瞭解如何解讀 HTTP 狀態碼及處理錯誤,請參閱「錯誤」一文。

限制和注意事項

  • 在 Google Chat API 中使用 Webhook 建立訊息時,回應不會包含完整訊息。回應只會填入 namethread.name 欄位。
  • Webhook 須遵守每個空間的配額限制:每秒 1 項要求,由空間中的所有 Webhook 共用。spaces.messages.create如果同一空間的查詢次數超過每秒 1 次,Chat 也可能會拒絕 Webhook 要求。如要進一步瞭解 Chat API 配額,請參閱「使用限制」一文。