こんにちは!今回はLINE Bot(Webhook)をCloudflare PagesなどのEdge環境で動かそうとしたときに、**「何もしていないのに500エラーが返ってくる…!」**という恐ろしい罠にハマったお話を共有します。
事象:いきなり500エラーでbotが無反応に
Nuxt 3 (Nitro) と @line/bot-sdk を使ってLINE Webhookのエンドポイントを実装し、いざCloudflare Pagesにデプロイ!
ルンルン気分でLINEからメッセージを送ってみると……あれ?既読すらつかない?
Cloudflare Pagesのログを確認すると、こんなエラーが吐き出されていました。
{
"message": "[unenv] crypto.createHmac is not implemented yet!",
"statusCode": 500
}
crypto.createHmac が実装されていない…?
原因:Node.js依存とEdge環境の壁
結論から言うと、LINE Bot SDKが提供している署名検証機能(validateSignature)が、Node.js標準の crypto モジュールにガッツリ依存していたことが原因でした。
Cloudflare Pagesのバックエンド(Workers/Edge環境)は、軽量で超高速な代わりに、Node.jsのフル機能(一部のコアモジュール)を持っていません。
Nuxt(Nitro)側で unenv という仕組みを使ってある程度Node.js環境をモック(擬似再現)してくれますが、crypto.createHmac まで完全にカバーされているわけではないため、SDK内部で呼び出した瞬間に「そんな関数ないよ!」と怒られて500エラーになっていたのです。
解決策:Web Crypto APIで自作する
SDKが使えないなら、Edge環境(ブラウザ環境)にも標準搭載されている Web Crypto API (crypto.subtle) を使って自分で署名検証ロジックを書いてしまえばOKです!
以下のように自作の検証関数を用意しました。
export const verifyLineSignature = async (
signature: string,
body: string,
channelSecret: string,
): Promise<boolean> => {
const encoder = new TextEncoder();
const key = await crypto.subtle.importKey(
"raw",
encoder.encode(channelSecret),
{ name: "HMAC", hash: "SHA-256" },
false,
["sign"],
);
const hmacBuffer = await crypto.subtle.sign(
"HMAC",
key,
encoder.encode(body),
);
// base64エンコード
const calculatedSignature = btoa(
String.fromCharCode(...new Uint8Array(hmacBuffer)),
);
return calculatedSignature === signature;
};
これを使ってWebhookの入口で await verifyLineSignature(...) を実行するようにしたところ、無事にエラーが消え、LINE側のリクエストを受け取れるようになりました!
Edge環境へのデプロイは高速で快適ですが、サードパーティ製SDKを使うときは「Node.jsモジュールに依存していないか?」に気をつける必要がありますね。皆さんもお気をつけください!