課題
Google Apps Script(GAS)からDiscordへWebhookでメッセージを送信する際,GASの共有IPアドレスが原因でDiscordのレートリミットに巻き込まれ,IPブロックされることがある:
Discord API Error (429): error code: 1015
この問題は自身の送信頻度が適正であっても発生する.
解決策
Cloudflare Workers(CFW)を用いて,リクエストをDiscordへ横流しするだけのプロキシを構築する.
- drop-in replacement: クライアント側の変更を最小限にするため,Base URLの置換だけで機能するようパスをそのまま引き継ぐ仕様とする.
- whitelist管理: セキュリティ対策として,
WH_というプレフィックスから始まるCloudflare Secretsに登録されたWebhook URLのみを許可する.
実装
index.tsのみ.
export interface Env {
[key: string]: unknown;
}
export default {
async fetch(
request: Request,
env: Env,
ctx: ExecutionContext,
): Promise<Response> {
if (request.method !== "POST") {
return new Response(JSON.stringify({ error: "Method Not Allowed" }), {
status: 405,
headers: { "Content-Type": "application/json" },
});
}
const requestUrl = new URL(request.url);
const pathname = requestUrl.pathname;
const targetWebhook = `https://discord.com${pathname}`;
const allowedWebhooks: string[] = Object.keys(env)
.filter((key) => key.startsWith("WH_") && typeof env[key] === "string")
.map((key) => env[key] as string);
if (!allowedWebhooks.includes(targetWebhook)) {
return new Response(
JSON.stringify({
error: "Forbidden: Webhook URL is not in the allowlist",
}),
{
status: 403,
headers: { "Content-Type": "application/json" },
},
);
}
const contentType =
request.headers.get("content-type") || "application/json";
try {
const body = await request.text();
const discordResponse = await fetch(targetWebhook, {
method: "POST",
headers: {
"Content-Type": contentType,
},
body: body,
});
const responseBody = await discordResponse.text();
return new Response(responseBody, {
status: discordResponse.status,
headers: {
"Content-Type":
discordResponse.headers.get("Content-Type") || "application/json",
},
});
} catch (error) {
return new Response(
JSON.stringify({ error: "Internal Server Error while forwarding" }),
{
status: 500,
headers: { "Content-Type": "application/json" },
},
);
}
},
};
使用方法
Webhook URLをWH_というプレフィックスから始まる名前でSecretsに登録し,送信元でdiscord.comをyour-worker.your-subdomain.workers.devに置換するだけ.
変更前:
https://discord.com/api/webhooks/123456789/ABCDEFG
変更後:
https://your-worker.your-subdomain.workers.dev/api/webhooks/123456789/ABCDEFG