LINE Webhook Verify thất bại? Xử lý đúng mảng events rỗng
Khi xác minh Webhook URL, LINE gửi một yêu cầu HTTP POST có mảng events rỗng. Bộ nhận cần kiểm tra chữ ký rồi trả về 200, không cố đọc tin nhắn hay gửi phản hồi. Nếu mã luôn giả định events[0] tồn tại, Verify có thể thất bại dù vẫn xử lý được tin nhắn thông thường. Ngược lại, Verify thành công cũng không chứng minh tin nhắn thật đã vào hàng đợi hoặc hộp thư hỗ trợ.
Điểm chính
- Yêu cầu
events: []đã được xác thực là phép kiểm tra kết nối hợp lệ, không phải tin nhắn bị mất. - Dùng channel secret và nội dung yêu cầu gốc để kiểm tra
x-line-signaturetrước khi phân tích JSON. - Kiểm thử kết nối và xử lý nghiệp vụ riêng biệt; kết quả này không thay thế kết quả kia.
- Webhook gốc của LINE và sự kiện chuẩn hóa của UnifyPort có hợp đồng khác nhau.
Nút Verify của LINE thực sự gửi gì?
Hướng dẫn xác minh Webhook URL chính thức nêu hai cách kiểm tra: API kiểm thử webhook và nút Verify trong LINE Developers Console. Cả hai kiểm tra khả năng LINE giao tiếp với máy chủ nhận. LINE yêu cầu bộ nhận trả về 200 cho yêu cầu kiểm tra không có sự kiện.
Dưới đây là cấu trúc nội dung trong ví dụ xác minh chữ ký của LINE, không phải tin nhắn khách hàng:
{"destination":"U8e742f61d673b39c7fff3cecb7536ef0","events":[]}
Không có đối tượng sự kiện để chứa tin nhắn, người gửi hay reply token. Đừng tạo hồ sơ khách hàng từ destination, tự tạo mã tin nhắn hoặc đưa phản hồi tự động vào hàng đợi. Nếu cần giám sát, hãy ghi nhận phép kiểm tra kết nối tách biệt với lưu lượng khách hàng.
Trước khi đổi URL, xác định thành phần nào đang quản lý điểm nhận. Nếu nhiều công cụ dùng chung tài khoản chính thức, tham khảo checklist webhook cho nhiều công cụ để tránh chuyển lưu lượng khỏi bộ nhận đang hoạt động trong lúc điều tra lỗi phân tích dữ liệu.
Xác thực trước, chấp nhận mảng rỗng sau
Hướng dẫn chữ ký của LINE quy định tính HMAC-SHA256 trên nội dung yêu cầu nhận được, dùng channel secret làm khóa và biểu diễn chữ ký bằng Base64. Đây không phải channel access token dùng để gọi API gửi tin.
Giữ nguyên các byte đầu vào. Phân tích JSON rồi tuần tự hóa lại có thể đổi khoảng trắng hoặc ký tự escape, khiến chữ ký không khớp. Mảng events rỗng không phải lý do bỏ kiểm tra xác thực: một bên không được phép cũng có thể gửi JSON cùng cấu trúc.
Hàm Node.js minh họa sau kiểm tra và phân tích yêu cầu LINE gốc. rawBody phải là Buffer nguyên bản do HTTP framework giữ lại; channelSecret lấy từ kho bí mật phía máy chủ. Đây không phải máy chủ hay hàng đợi lưu trữ bền vững hoàn chỉnh.
import { createHmac, timingSafeEqual } from 'node:crypto';
export function readLineEvents(rawBody, signature, channelSecret) {
if (!Buffer.isBuffer(rawBody) || !channelSecret) {
throw new Error('Raw body and channel secret are required');
}
const expected = createHmac('sha256', channelSecret)
.update(rawBody)
.digest('base64');
const supplied = Buffer.from(signature ?? '', 'utf8');
const calculated = Buffer.from(expected, 'utf8');
if (supplied.length !== calculated.length ||
!timingSafeEqual(supplied, calculated)) {
return { status: 401 };
}
try {
const payload = JSON.parse(rawBody.toString('utf8'));
if (!payload || !Array.isArray(payload.events)) {
return { status: 400 };
}
return { status: 200, events: payload.events };
} catch {
return { status: 400 };
}
}
Các nhánh 400 và 401 là lựa chọn phòng vệ của ví dụ, không phải mã lỗi LINE API. Tích hợp kết quả theo thứ tự sau:
- Truyền header
x-line-signaturevà nội dung chưa chỉnh sửa vào hàm. - Từ chối yêu cầu không hợp lệ mà không tạo tác vụ nghiệp vụ.
- Nếu xác minh thành công và
events.length === 0, trả HTTP200ngay. - Nếu có sự kiện, lưu bền vững trước khi xác nhận nhận thành công; xử lý công việc chậm ở chế độ bất đồng bộ. Nếu lưu thất bại, đừng trả
200chỉ vì hàm đã trả trạng thái đó.
LINE khuyến nghị xử lý bất đồng bộ. Thiết kế lưu trữ và worker vẫn thuộc trách nhiệm của ứng dụng. Hãy duyệt toàn bộ mảng thay vì chỉ lấy phần tử đầu tiên.
Xác định đúng khâu gặp lỗi
| Quan sát | Kiểm tra tiếp |
|---|---|
| Không có yêu cầu tới ứng dụng | Host và đường dẫn cấu hình, TLS, định tuyến đầu vào, log proxy |
| Xác minh chữ ký thất bại | Đúng channel secret, giữ nguyên byte gốc, chuyển tiếp header |
| Yêu cầu rỗng đã xác minh gây ngoại lệ | Truy cập vô điều kiện vào sự kiện đầu tiên, tin nhắn hoặc reply token |
| Ứng dụng báo thành công nhưng Verify thất bại | Trạng thái thực tế do điểm vào công khai trả về và thời gian xử lý |
| Verify thành công nhưng hộp thư không có tin | Lưu trữ sự kiện thật, định tuyến và thực thi worker |
Đừng đổi thông tin xác thực hay đơn vị quản lý webhook chỉ vì bộ xử lý dành cho tin nhắn từ chối mảng rỗng. Nếu sự kiện thật tới nhưng thiếu reply token, đó là vấn đề khác: hướng dẫn chế độ standby của LINE giải thích quyền phản hồi. Yêu cầu xác minh rỗng không có sự kiện, nên cũng không có mode của sự kiện để kiểm tra.
Kiểm tra kết nối và tin nhắn riêng biệt
Đây là các tình huống nghiệm thu được đề xuất, không phải kết quả kiểm thử thực tế đã ghi nhận:
- Yêu cầu rỗng có chữ ký đúng nhận
200, không tạo tin nhắn khách hàng hay tác vụ gửi. - Cùng nội dung rỗng nhưng thiếu chữ ký hoặc chữ ký sai bị từ chối.
- Yêu cầu không rỗng có chữ ký đúng được lưu bền vững trước khi xác nhận.
- Sau khi Verify thành công, gửi một tin nhắn kiểm thử có kiểm soát đến đúng tài khoản chính thức và theo dõi nó trong quy trình hộp thư dự kiến.
- Lỗi lưu trữ không bị đánh dấu nội bộ là xử lý xong chỉ vì chữ ký hợp lệ.
Chỉ ghi dữ liệu chẩn đoán cần thiết như kết quả xác minh, số sự kiện, trạng thái HTTP và thời điểm quan sát. Không đưa channel secret, reply token hoặc nội dung tin nhắn khách hàng vào log thông thường.
Tách riêng bộ nhận UnifyPort
Giao diện không chính thức của UnifyPort kết nối tài khoản LINE qua quy trình ủy quyền LINE, không phải dịch vụ kiểm thử webhook gốc của tài khoản chính thức.
Hợp đồng phân phối webhook dùng X-Device-Signature: khi cấu hình signing_secret, chữ ký là HMAC-SHA256 của X-Device-Timestamp, một dấu chấm và nội dung gốc, được mã hóa dạng thập lục phân. Lớp bao chuẩn hóa chứa id, type, provider, account_id, occurred_at và data, thay vì mảng events của LINE.
Dùng route riêng hoặc cấu hình bộ nhận phân biệt rõ hai hợp đồng. Không được coi payload UnifyPort thiếu events gốc là yêu cầu xác minh rỗng của LINE. Điều này cũng quan trọng khi cùng hệ thống xử lý thêm WhatsApp hoặc Zalo: phải chọn hợp đồng đầu vào trước khi phân loại dữ liệu.
LINE Verify thành công không kiểm tra việc phân phối UnifyPort, ủy quyền tài khoản hay xử lý tin nhắn chuẩn hóa. Nếu danh tính cần dùng là LINE Official Account, hãy giữ đường tích hợp Messaging API chính thức.
Câu hỏi thường gặp
events: [] có phải lỗi không?
Không phải trong yêu cầu xác minh Webhook URL của LINE. Xác thực rồi trả 200, không tạo tác vụ tin nhắn. Trường bị thiếu hoặc sai kiểu không tương đương với mảng rỗng.
Vì sao tin nhắn thường hoạt động nhưng Verify thất bại?
Một lỗi triển khai thường gặp là giả định mọi yêu cầu đều có sự kiện tin nhắn đầu tiên. Kiểm tra phản hồi thực tế và log ngoại lệ; lỗi truyền tải hoặc chữ ký cũng có thể khiến kiểm thử thất bại.
Xác minh thành công có chứng minh bot trả lời được không?
Không. Đây là kiểm tra giao tiếp với bộ nhận, không kiểm tra lưu trữ, worker, điều kiện được phép trả lời hay kết quả gọi API gửi tin.
Bước tiếp theo và nguồn
Với tài khoản chính thức, chạy kiểm tra Webhook URL của LINE, rồi theo dõi một tin nhắn kiểm thử thật. Với tích hợp UnifyPort độc lập, triển khai theo hợp đồng webhook trong tài liệu.
Nguồn chính thức được kiểm tra ngày 2026-10-28:
Biến tích hợp nhắn tin thành một pipeline sản phẩm ổn định.
Bắt đầu bằng cách gửi qua một API, rồi đưa mọi tin nhắn inbound trở lại hệ thống kinh doanh bằng sự kiện chuẩn.