チュートリアル

@line/bot-sdk Express Middleware:replyMessage と validateSignature の完全な実例

@line/bot-sdk Express middleware の実用例:webhook 署名検証、replyMessage と sentMessages、エラー処理、TypeScript 型定義。本番対応コード。

LineBot.pro Team11 分で読めます
@line/bot-sdk Express Middleware:replyMessage と validateSignature の完全な実例

#なぜ Express Middleware が必要?

公式 @line/bot-sdk には Express 互換 middleware が同梱されており、手作業だと再実装が面倒な 2 つの処理を担います:

  1. webhook 署名検証x-line-signature ヘッダー)を HMAC-SHA256 で検証
  2. JSON body の parse と署名不一致時の HTTP 401 拒否

既に開発中なら LINE チャットボット開発LINE API 統合 も併読してください。

#インストールとプロジェクト設定

bash
npm init -y
npm i express @line/bot-sdk
npm i -D typescript @types/express ts-node-dev
bash
LINE_CHANNEL_ACCESS_TOKEN=...
LINE_CHANNEL_SECRET=...

#最小動作例

ts
import express from "express"
import { middleware, messagingApi, WebhookEvent } from "@line/bot-sdk"

const config = {
  channelAccessToken: process.env.LINE_CHANNEL_ACCESS_TOKEN!,
  channelSecret: process.env.LINE_CHANNEL_SECRET!,
}
const client = new messagingApi.MessagingApiClient({ channelAccessToken: config.channelAccessToken })

const app = express()
app.post("/webhook", middleware(config), async (req, res) => {
  const events: WebhookEvent[] = req.body.events
  await Promise.all(events.map(handleEvent))
  res.status(200).end()
})

async function handleEvent(event: WebhookEvent) {
  if (event.type !== "message" || event.message.type !== "text") return
  const r = await client.replyMessage({
    replyToken: event.replyToken,
    messages: [{ type: "text", text: `Echo: ${event.message.text}` }],
  })
  console.log(r.sentMessages.map(m => m.id))
}

app.listen(3000)

LINE Bot webhook architecture
LINE Bot webhook architecture

#validateSignature() の動作

ts
import crypto from "node:crypto"

function validateSignature(body, secret, signature) {
  const computed = crypto.createHmac("sha256", secret).update(body).digest("base64")
  return crypto.timingSafeEqual(Buffer.from(computed), Buffer.from(signature))
}

失敗ケース:

  • express.json() を middleware より先に設定
  • リバースプロキシが Content-Length を書き換え
  • channelSecret の末尾に改行

#replyMessage(replyToken, ...) — 完全例

replyToken30 秒以内 に使用、1 回のみ。

ts
await client.replyMessage({
  replyToken: event.replyToken,
  messages: [
    { type: "text", text: "こんにちは!" },
    { type: "flex", altText: "予約確認", contents: { type: "bubble", body: { type: "box", layout: "vertical", contents: [{ type: "text", text: "予約確認", weight: "bold" }] } } },
  ],
})

1 回の replyMessage で 最大 5 メッセージまで。

#ReplyMessageResponse.sentMessages

SDK v9(2024)以降:

ts
type ReplyMessageResponse = {
  sentMessages: Array<{ id: string; quoteToken?: string }>
}

#エラー処理と 401/400

エラー原因解決
401 SignatureValidationFailedexpress.json() が先webhook より前で削除
400 Invalid reply tokenトークン使用済 or 30秒超pushMessage 使用

#LINE Bot Webhook アーキテクチャ

LINE → Webhook(middleware が HMAC 検証) → handleEvent → replyMessage → LINE

LINE bot builder 比較Rich Menu サイズ も参照。

#よくある質問

Q: Express middleware はどこに置く? webhook ルートに直接、express.json() より前に

Q: validateSignature() を Express 外で呼ぶには? import { validateSignature } from "@line/bot-sdk" で raw body と署名を渡す。

Q: sentMessages には何が入っている? id(永続的な LINE メッセージ ID)と任意の quoteToken の配列。


次のステップ:

LineBot.pro

LINEビジネスを自動化する準備はできましたか?

LineBot.proでLINEコミュニケーションの自動化を今すぐ始めましょう。