บทเรียน

@line/bot-sdk Express Middleware: ตัวอย่างพร้อมใช้งานจริง พร้อม replyMessage & validateSignature

ตัวอย่างโค้ดสำหรับ @line/bot-sdk Express middleware: signature validation, replyMessage พร้อม sentMessages, error handling และ TypeScript types พร้อม production

LineBot.pro Team11 นาทีอ่าน
@line/bot-sdk Express Middleware: ตัวอย่างพร้อมใช้งานจริง พร้อม replyMessage & validateSignature

#ทำไมต้อง Express Middleware?

@line/bot-sdk ทางการมี Express middleware ที่ทำ 2 สิ่งที่คุณต้องเขียนเองมิฉะนั้น:

  1. ตรวจสอบ webhook signature (x-line-signature header) ด้วย HMAC-SHA256
  2. Parse JSON body และปฏิเสธ request ที่ลายเซ็นผิดด้วย HTTP 401

ถ้าไม่ใช้ ต้องอ่าน raw body เอง (express.json() กิน body ก่อน HMAC) คำนวณลายเซ็นใหม่ และ time-constant compare

กำลังพัฒนา? อ่านควบคู่กับ คู่มือ LINE chatbot และ LINE API integration

#ติดตั้ง & ตั้งค่าโปรเจ็กต์

bash
npm init -y
npm i express @line/bot-sdk
npm i -D typescript @types/express @types/node ts-node-dev
bash
# .env
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()

// สำคัญ: อย่าเรียก express.json() ก่อน middleware()
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 reply = await client.replyMessage({
    replyToken: event.replyToken,
    messages: [{ type: "text", text: `Echo: ${event.message.text}` }],
  })
  console.log("sent message ids:", reply.sentMessages.map(m => m.id))
}

app.listen(3000)

LINE Bot webhook architecture
LINE Bot webhook architecture

#validateSignature() ทำงานอย่างไร

Express middleware เรียก validateSignature(body, channelSecret, signature) ภายใน:

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),
  )
}

ถ้าผิด middleware ตอบ HTTP 401 พร้อม SignatureValidationFailed คุณจะเจอเมื่อ:

  • ใส่ express.json() ก่อน middleware(config)
  • Reverse proxy แก้ Content-Length หรือ charset
  • channelSecret มี trailing newline

#replyMessage(replyToken, ...) — ตัวอย่างเต็ม

replyToken ใช้ได้ภายใน 30 วินาที และใช้ครั้งเดียว

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", size: "lg" },
          ],
        },
      },
    },
  ],
})

ส่งได้สูงสุด 5 messages ต่อ replyMessage ครั้งเดียว

#ReplyMessageResponse.sentMessages

ตั้งแต่ SDK v9 (2024) replyMessage ส่งคืน ReplyMessageResponse ที่มี sentMessages:

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

#Error Handling & 401/400

Errorสาเหตุแก้
401 SignatureValidationFailedexpress.json() ก่อน middlewareลบ JSON parser ก่อน /webhook
400 Invalid reply tokenToken เก่าหรือใช้ซ้ำReply ครั้งเดียว เร็ว ใช้ pushMessage แทนถ้าหน่วง
400 ต้อง <= 5 messagesarray ยาวเกินแยก replyMessage + pushMessage

#LINE Bot Webhook Architecture

LINE Platform → Webhook (middleware ตรวจ HMAC) → handleEvent → replyMessage → LINE

ดูระดับ solution ใน LINE bot builder comparison และ Rich Menu สำหรับ navigation

#คำถามที่พบบ่อย

Q: วาง Express middleware ตรงไหน? ใส่บน webhook route ตรง ๆ ก่อน express.json() ใด ๆ

Q: เรียก validateSignature() นอก Express ได้ไหม? ได้ import { validateSignature } from "@line/bot-sdk" ส่ง raw body, channel secret, และ x-line-signature

Q: ReplyMessageResponse.sentMessages มีอะไร? Array ของ id (LINE message ID) และ quoteToken (เลือก) ตามลำดับเดียวกับ messages

Q: ใช้ replyMessage + pushMessage พร้อมกันได้ไหม? ได้ replyMessage ฟรี ใน 30 วินาที pushMessage นับโควตา


ขั้นตอนต่อไป:

บริการที่เกี่ยวข้อง

LineBot.pro

พร้อม Automate ธุรกิจ LINE ของคุณหรือยัง?

เริ่มทำให้การสื่อสาร LINE ของคุณเป็นอัตโนมัติกับ LineBot.pro วันนี้