對於經營開源專案來說,用 Discord 來打造交流平台確實是我目前所見最佳的選項。本文來分享一些 BP Studio 使用 Discord 的心得。

簡介

最一開始,BP Studio 單純就只有 GitHub Issues 可以作為使用者回饋意見的管道,後來我又開啟了 GitHub Discussions 的功能,希望可以帶來多一點的討論,不過成效都不怎麼好。我想主要的原因在於,GitHub 終究是一個比較針對開發者的平台,一般的使用者大多甚至不會在那邊註冊帳號,更不用說貼文或討論了。

於是,我從 2022 年初開始開設了 BP Studio 專屬的 Discord 伺服器。直到本文寫成為止已經過了三年多,這個伺服器上的討論雖然遠遠談不上熱絡、但是確實三不五時會有新手上來問一些問題、且也有熱心的使用者會願意幫我回答,光是這樣就已經幫上超大的忙了。

當然,想靠一個平台就把所有相關的討論都吸收進來、天底下是絕對沒有這麼神奇的事情的。也是有很多人沒在用 Discord 的、而會選擇到 Reddit 或其它平台的摺紙相關版面發問。又或者,即便是在 Discord 上,同樣也有很多人選擇在規模更大的摺紙社團伺服器發問、而不是到我這邊來。此外,雖然偶爾也會有人到我這邊來分享他們的作品,但大多數時候人們還是比較會選擇貼在自己的社群平台版面中,這也是可以理解的。

儘管如此,有專屬的 Discord 還是勝過沒有來得好很多。跟別的平台相比,Discord 的優點至少有:

  1. 多層次的「伺服器 → 分類 → 頻道」架構,可以很好地組織版面與討論。
  2. 權限管理非常精細,對於委派其他人當管理者等等角色很方便。
  3. 非常適合即時的對話,同時剛好也在線上的人要加入也非常容易。
  4. 完整支援 Markdown,很適合跟程式有關的討論 1
  5. 擁有非常豐富的機器人生態與 Webhook 整合能力,可以玩出很多自訂的功能,這也尤其合開發者的品味。

其中 Webhook 的部份就是本篇的主題,底下繼續深入說明。

Discord Webhook

簡單來說,Discord Webhook 就是一個可以允許其它應用程式對 Discord 伺服器上特定頻道進行操作(尤其是發送訊息)的一個 API 端點。一個 webhook 只會對應一個頻道,所以如果會需要自動發訊息到多個頻道的話,就必須建立多個 webhook。建立 webhook 的方法是到「伺服器設定 → 整合 → Webhook」當中點選「新 Webhook」、設定其名稱與對應的頻道即可。接著點選底下的「複製 Webhook 網址」,就會得到一個形如

https://discord.com/api/webhooks/{webhook.id}/{webhook.token}

這樣的網址端點,然後其它應用程式就可以透過這個端點來發訊息到指定的頻道中。發送訊息用的是 POST 方法,格式有兩種:直接發送 application/json 格式,或是使用 multipart/form-data(有要同時上傳附加檔案的話,就必須採用這種)。在前者的情況中,資料格式主要有:

{
    "content": "訊息內容",
    "username": "選填,發言者的顯示名稱;不指定的話即為 webhook 名稱",
    "avatar_url": "選填,發言者的顯示圖示;不指定的話即為 webhook 圖示"
}

其它一些比較少用的欄位可以參考官方文件。而在後者的情況中,上面的這些資料必須轉換成 JSON 字串然後放在 payload_json 裡面,而要上傳的檔案則是用 files[0]files[1]……這樣的欄位名稱(或者如果只有一個檔案,也可以叫 file)。以 JavaScript 來實作的話,就會是這樣:

const payload = { content: "訊息內容" };
const blob = new Blob(...); // 在這邊產生要上傳的檔案
const formData = new FormData();
formData.append("payload_json", JSON.stringify(payload));
formData.append("file", blob, "上傳的檔名");

fetch("https://discord.com/api/webhooks/.../...", {
    method: "POST",
    body: formData,
});

值得注意的是,webhook 網址是 id 和 token 兩者都明文寫出來的,也就是說拿到這個網址的人就有辦法進行一切 webhook 能做的操作(包括發送垃圾訊息、竄改 webhook 已經發送過的訊息、或甚至刪除掉 webhook 本身),因此 webhook 網址是只能讓信任的應用程式私藏著的、而不能例如公開地寫在 GitHub 上的程式碼當中的 2。個人是希望他們未來可以改進一下設計、產生一個權限較小的可公開網址之類的,但是目前是還沒有這種功能。

底下介紹幾個 BP Studio 裡面的 webhook 應用。

Checkly

首先是我在另一篇文章中介紹過的 Checkly。整合之後,就可以在 Checkly 進行自動測試遇到各種失敗情況的時候、傳送通知到指定的 Discord 頻道來(通常會是一個限定管理者觀看的頻道)。

要整合 Checkly 跟 Discord,只要在「Alerts」的頁面中點選「Add more channels」按鈕,選擇 Discord、隨便取個名稱、然後把 webhook 的網址貼上去儲存即可。美中不足的是,Checkly 並沒有提供一個簡便的功能、可以讓我們發送測試訊息來確定到底 webhook(或是其它的 alert channel)設定成功了沒有;唯一的測試方法就是故意寫一個一定會失敗的測試去給它跑。

GitHub

GitHub 也有提供 webhook 整合功能,但是它走的是它自己的格式,跟 Discord 的 webhook 格式完全不一樣。幸好 Discord 很貼心,在他們自己的 webhook 當中提供了一個 GitHub 專用的變種。要使用該端點,只要在通常的 webhook 網址後面再加上 github 就是了:

https://discord.com/api/webhooks/{webhook.id}/{webhook.token}/github

要設定整合,可以到 GitHub repo 的「Settings → Webhooks」點選「Add webhook」按鈕,然後把專用網址貼上,設定內容類型為 application/json,然後再底下如果選擇「Let me select individual events」就可以精確地指定發生哪些事情(例如推送、有人給星……)的時候要傳送通知過來。將這些通知送到一個公開的頻道當中,會很有助於讓使用者知道專案的持續維護進度、增進使用者黏著度。

錯誤回報

在本系列的第 19 篇中,我介紹過 BP Studio 攔截核心錯誤並且自動把錯誤 log 上傳的機制。當時我採用的是 Filestack,但尤其隨著 Filestack 在 2025 年五月底終止免費方案之後,我就更加覺得應該要遷移過來改用 Discord Webhook 會更方便,尤其是我即使是用手機也可以即時收到通知這一點。

可是對 BP Studio 來說,這邊卻有一個頭大之處。BP Studio 本身是一個純前端的程式,於是如果用它來直接呼叫 webhook 的話,無論如何都會把 webhook 的網址整個暴露出來:就算我用了各種混淆(obfuscate)的手法來讓原始碼難以閱讀,反正最終呼叫的網址到瀏覽器的 console 去一看就知道了,根本藏都藏不住。而這樣一來就跟前面提到的、webhook 網址不能曝光這一點有衝突了。關於這個問題,大抵就是兩個解法:

  1. 盡可能混淆程式碼,然後原則上因為 webhook 的呼叫只有在發生核心錯誤的時候會發生,理論上此時面對的使用者應該是一個深度使用的忠實使用者才對,我應該可以信任他不會濫用 webhook 網址。
  2. 使用一個後端的 proxy 來把發送訊息的請求轉發給 Discord Webhook;或者用現成的、或者就是自己做一個。

最後我還是決定採用第二種解法,比較不會心有不安。截至本文寫成(2025)為止,能夠作到這種請求轉發的現成免費服務有:

服務 免費方案額度 持續免費可能性 3
Webhook Relay 每月 150 次 ⭐⭐⭐⭐
Hookdeck 每月 10000 次 ⭐⭐⭐
Svix 每月 50000 次 ⭐⭐⭐⭐⭐
Hookrelay 每天 100 次

這些當然都可以試試看,但有了 Filestack 的經驗之後,天曉得這些服務什麼時候又會終止免費方案,這樣下去也還是沒有解決問題;況且自己寫一個這種轉發的 proxy 端點也沒有很困難(當然,前提是自己有一個伺服器可以用),所以我就選擇自己用 PHP 寫一個簡單的了。其程式碼如下:

<?php
// 設定 CORS 檔頭(因為我這支程式是放在另一個網域上)
header('Access-Control-Allow-Origin: https://bpstudio.abstreamace.com');
header('Access-Control-Allow-Methods: POST, OPTIONS');
header('Access-Control-Allow-Headers: Content-Type');

// 處理 OPTIONS 請求
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
    http_response_code(204); // No Content
    exit;
}

// 從伺服器的環境變數中讀取 Discord Webhook 網址,避免明文寫在程式碼裡
$webhook_url = $_SERVER['DISCORD_WEBHOOK'];

// 檢查請求為 POST 方法
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
    http_response_code(405);
    echo json_encode(['error' => 'Only POST requests are allowed.']);
    exit;
}

// 準備 multipart/form-data 的欄位
$post_fields = [];

// 寫入字串欄位
foreach ($_POST as $key => $value) {
    $post_fields[$key] = $value;
}

// 處理檔案上傳
if (!empty($_FILES)) {
    foreach ($_FILES as $key => $file) {
        if (is_array($file['tmp_name'])) {
            foreach ($file['tmp_name'] as $index => $tmp_name) {
                if (is_uploaded_file($tmp_name)) {
                    $post_fields[$key . "[$index]"] = new CURLFile(
                        $tmp_name,
                        $file['type'][$index],
                        $file['name'][$index]
                    );
                }
            }
        } else {
            if (is_uploaded_file($file['tmp_name'])) {
                $post_fields[$key] = new CURLFile(
                    $file['tmp_name'],
                    $file['type'],
                    $file['name']
                );
            }
        }
    }
}

// 用 cURL 來發起請求
$ch = curl_init($webhook_url);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $post_fields);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

$response = curl_exec($ch);
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);

if ($response === false) {
    http_response_code(500);
    echo json_encode([
        'error' => 'Failed to forward the request.',
        'details' => curl_error($ch)
    ]);
} else {
    http_response_code($http_code);
    echo $response;
}

curl_close($ch);
?>

這只是最陽春的轉發,本身沒有加上任何的安全防護,所以還是有被濫用的可能,但是頂多只是垃圾訊息而已,是可以接受的風險;要是真的被攻擊再加強吧。


  1. 但是相對的,Discord 目前並沒有內建 LaTeX 的支援,不過可以透過像 MathBotTeXit 之類的機器人來達成這個功能。 

  2. 如果你這麼做的話,不用多久你就會收到一個來自「Webhook Safety」的 Discord 伺服器的訊息,說你的這個 webhook 網址已經外洩了,除非你請他們把你的網址加入白名單當中、否則他們為了安全起見就會在一定的時間之後幫你把這個 webhook 刪除掉(就像我說的,任何拿到網址的人本來就能作到這一點)。我不確定這個 Webhook Safety 伺服器是不是 Discord 官方經營的(老實說,看起來有一點不像),但是至少他們確實顯示出了 webhook 網址洩漏的結果會如何。 

  3. 這是我用 ChatGPT 根據這些公司的成立時間、公司規模、企業用戶數與資金穩定度去分析的結果。 


分享此頁至:
最後修改日期: 2025/05/18

留言

撰寫回覆或留言

發佈留言必須填寫的電子郵件地址不會公開。您的留言可能會在審核之後才出現在頁面上。