疑問
honoでLINE message APIを受け取るWebhook APIを作るときに何をすればよいか?
回答
HonoでLINEのWebhookを作成するには、主に以下の3つのステップが必要です。
- リクエストの署名検証
- リクエストボディのパースとイベント処理
- LINEサーバーへの応答
手順
-
Honoプロジェクトの準備
npm create hono@latestでプロジェクトを作成します。Node.js環境を想定します。 -
環境変数の設定 LINE Developersコンソールから取得した2つの値を設定します。
LINE_CHANNEL_SECRET: 署名検証に使うチャネルシークレットLINE_CHANNEL_ACCESS_TOKEN: メッセージ返信に使うチャネルアクセストークン(長期)
-
Webhookエンドポイントの実装
以下は、Node.jsランタイムで動作するHonoのサンプルコードです。
import { Hono } from 'hono'
import { HTTPException } from 'hono/http-exception'
import type { MessageEvent, TextMessage } from '@line/bot-sdk'
import crypto from 'crypto'
const app = new Hono()
// 環境変数から設定を取得
const CHANNEL_SECRET = process.env.LINE_CHANNEL_SECRET!
const CHANNEL_ACCESS_TOKEN = process.env.LINE_CHANNEL_ACCESS_TOKEN!
// LINEからのリクエストの署名を検証する関数
const verifySignature = (signature: string, body: string): boolean => {
const hash = crypto
.createHmac('sha256', CHANNEL_SECRET)
.update(body)
.digest('base64');
return signature === hash;
};
// Webhook用のPOSTエンドポイント
app.post('/webhook', async (c) => {
// 1. 署名検証
const signature = c.req.header('x-line-signature');
const body = await c.req.text(); // JSONパース前に生テキストを取得
if (!signature || !verifySignature(signature, body)) {
throw new HTTPException(401, { message: 'Invalid signature' });
}
// 2. イベント処理
const data = JSON.parse(body);
const events: MessageEvent[] = data.events;
for (const event of events) {
if (event.type === 'message' && event.message.type === 'text') {
const message: TextMessage = event.message;
const replyToken = event.replyToken;
// 3. メッセージを返信する (オウム返し)
await fetch('https://api.line.me/v2/bot/message/reply', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${CHANNEL_ACCESS_TOKEN}`,
},
body: JSON.stringify({
replyToken: replyToken,
messages: [{
type: 'text',
text: message.text, // 受け取ったテキストをそのまま返す
}],
}),
});
}
}
// LINEサーバーに正常処理を通知
return c.json({ status: 'ok' });
});
export default app
要点
- 署名検証が最重要:
x-line-signatureヘッダーとリクエストボディ、そしてチャネルシークレットを使って、リクエストがLINEから来た本物であることを確認します。 - 生のボディテキストが必要: Honoの
c.req.json()はボディを消費してしまうため、署名検証にはc.req.text()で先に生のテキストを取得します。 - 非同期で返信: Webhookのレスポンスとしてメッセージを返すのではなく、LINEのReply API (
/v2/bot/message/reply) を別途fetchなどで呼び出します。 - 200 OKを返す: イベント処理が終わったら、LINEサーバーに
200 OKを返す必要があります。Honoではc.json({ status: 'ok' })などで応答します。