※本記事は、実際に発生した開発トラブルの解決事例に基づき、構成および執筆に生成AIを使用しています。記載内容は技術者による実機検証・レビュー済みですが、ご利用の際は環境に合わせて十分な検証を行ってください。

こんにちは!今回は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モジュールに依存していないか?」に気をつける必要がありますね。皆さんもお気をつけください!