เชื่อมบอท Facebook Messenger แล้วบอทไม่ตอบ: 7 จุดที่ต้องเช็ค เรียงจากที่ลืมบ่อยที่สุด
อาการที่เจอบ่อยที่สุดตอนทำบอท Facebook Messenger คือ ยืนยัน webhook ผ่านแล้ว ขึ้นเครื่องหมายถูกเขียว แต่พอทักเพจ บอทเงียบ และฝั่งเซิร์ฟเวอร์ไม่มี request เข้ามาเลยสักครั้ง
ผมเจอเองตอนต่อบอทให้เพจร้านค้าจริง เสียเวลาไล่โค้ดไปนาน ทั้งที่โค้ดไม่ได้ผิด ต้นเหตุคือปุ่มเปิดปิดปุ่มเดียวในหน้าตั้งค่าของ Meta บทความนี้รวมจุดที่ต้องเช็คเรียงจากที่ลืมบ่อยที่สุด
1. ยังไม่ได้เปิด field messages ใน Webhooks
การยืนยัน webhook (ที่ Meta ส่ง hub.challenge มาให้ตอบ) เป็นแค่การบอกว่า URL นี้ใช้ได้
ยังไม่ได้แปลว่า Meta จะส่งข้อความมาให้ ต้องเลือกด้วยว่าจะรับ event อะไรบ้าง
ในหน้าตั้งค่า Messenger API ของแอป ส่วน Webhooks ของเพจนั้น ให้เปิด field messages
(และ messaging_postbacks ถ้าใช้ปุ่ม) ถ้าไม่เปิด Meta ไม่ส่งข้อความมาเลย
และไม่มี error แจ้งที่ไหน
2. ยังไม่ได้ subscribe แอปเข้ากับเพจ
แอปต้องผูกกับเพจด้วย (subscribed apps) ทำได้จากหน้าตั้งค่าโดยกดเพิ่มเพจ หรือเรียก Graph API
POST /{page-id}/subscribed_apps ด้วย page access token
ข้อนี้กับข้อ 1 ต้องทำทั้งคู่ ทำแค่อย่างใดอย่างหนึ่งไม่พอ
3. แอปยังอยู่โหมดพัฒนา และคนที่ทักไม่มีบทบาทในแอป
ตอนแอปยังไม่เผยแพร่ หรือยังไม่ได้สิทธิ์ใช้งานระดับที่ต้องผ่าน App Review บอทจะตอบเฉพาะคน ที่มีบทบาทในแอป (Admin / Developer / Tester) คนทั่วไปทักมาจะไม่มีอะไรเกิดขึ้น ทดสอบด้วยบัญชีที่ไม่มีบทบาทในแอปทุกครั้ง ก่อนบอกลูกค้าว่าระบบพร้อม
4. Page access token หมดอายุ
token ที่ได้จาก Graph API Explorer เป็น token อายุสั้น ใช้ได้ไม่กี่ชั่วโมง
บอทจะทำงานวันแรกแล้วเงียบไปในวันถัดมา วิธีที่ใช้ได้คือแลก user token เป็นแบบอายุยาว
แล้วเรียก /me/accounts เพื่อเอา page token ของเพจ
page token ที่ได้จากวิธีนี้ปกติไม่มีวันหมดอายุ (จนกว่าจะเปลี่ยนรหัสผ่านหรือถอนสิทธิ์)
ตรวจอายุ token ได้ที่เครื่องมือ Access Token Debugger ของ Meta
5. Page ID ไม่ตรง
ถ้าระบบรองรับหลายเพจ และเลือกคำตอบตาม Page ID ที่มากับ webhook (entry[].id)
ให้เอา ID จาก Graph API จริงมาเทียบ อย่าคัดลอกจากเอกสารหรือแชท เพราะพิมพ์ผิดง่ายมาก
ID ที่ผิดหนึ่งหลักทำให้ระบบหาร้านไม่เจอ แล้วไปตอบด้วยค่าตั้งต้น หรือไม่ตอบเลย
6. ไม่ได้ตรวจลายเซ็น หรือตรวจผิดวิธี
Meta ส่ง header X-Hub-Signature-256 มากับทุก webhook ควรตรวจด้วย App Secret
เพื่อกันคนอื่นยิงมาปลอม แต่ถ้าตรวจผิด (เช่น อ่าน body ที่ถูกแปลงเป็น JSON แล้วมาคำนวณ แทน body ดิบ)
ทุก request จะถูกปฏิเสธ และบอทจะเงียบ
import hmac, hashlib
def valid_signature(raw_body: bytes, header: str, app_secret: str) -> bool:
expected = "sha256=" + hmac.new(app_secret.encode(), raw_body, hashlib.sha256).hexdigest()
return hmac.compare_digest(expected, header or "")
# Flask: ใช้ request.get_data() (bytes ดิบ) ไม่ใช่ json.dumps(request.json)
7. บอทตอบซ้ำ 2 รอบ — ตอบ webhook ช้าเกินไป
อาการนี้กลับกัน คือบอทไม่เงียบ แต่ตอบซ้ำ สาเหตุที่พบบ่อยคือเซิร์ฟเวอร์เรียก AI แล้วรอคำตอบ ก่อนตอบ webhook ว่า 200 ถ้าช้าเกินไป Meta ถือว่าส่งไม่สำเร็จแล้วส่ง event เดิมมาซ้ำ บอทก็ตอบรอบที่สอง
วิธีแก้:
- ตอบ 200 ให้ Meta ทันทีที่รับ event แล้วค่อยประมวลผลใน thread หรือคิวแยก
- จำ
message.midที่เคยประมวลผลไว้ ถ้าเจอซ้ำให้ข้าม - ลูกค้ามักพิมพ์ทีละหลายบรรทัด ถ้าตอบทุกบรรทัดจะได้คำตอบหลายข้อความ ให้รอสักครู่ (debounce) เพื่อรวมข้อความจากคนเดียวกันก่อน แล้วตอบครั้งเดียว
ลำดับการไล่ปัญหาที่แนะนำ
- ดู log ว่ามี POST เข้ามาไหมตอนทักเพจ — ถ้าไม่มี ไล่ข้อ 1, 2, 3
- มี POST เข้ามา แต่ตอบไม่ออก — ดู response ตอนเรียก Send API ไล่ข้อ 4, 5
- มี POST แต่โดนปฏิเสธที่ฝั่งเรา — ไล่ข้อ 6
- ตอบได้แต่ซ้ำ — ข้อ 7
Meta เปลี่ยนชื่อเมนูและหน้าตั้งค่าบ่อย ถ้าหาเมนูตามชื่อในบทความไม่เจอ ให้ค้นในเอกสาร Messenger Platform ของ Meta for Developers ด้วยคำว่า webhook fields