Webhooks
รับการแจ้งเตือนแบบเรียลไทม์สำหรับเหตุการณ์ AnyCrawl ทั้งหมด รวมถึงการดึงข้อมูล การครอล การแมป การค้นหา และงานตามกำหนดเวลา
บทนำ
Webhooks ให้คุณรับการแจ้งเตือน HTTP แบบเรียลไทม์เมื่อมีเหตุการณ์ในบัญชี AnyCrawl แทนการ poll อัปเดต AnyCrawl ส่งคำขอ POST ไปยังเอนด์พอยต์ที่คุณกำหนดเมื่อเหตุการณ์เกิดขึ้น
คุณสมบัติหลัก: สมัครรับหลายชนิดเหตุการณ์ การตรวจสอบลายเซ็น HMAC-SHA256 การลองใหม่แบบ exponential backoff การติดตามประวัติการส่ง และการป้องกัน IP ส่วนตัว
คุณสมบัติหลัก
- สมัครเหตุการณ์: การดึงข้อมูล การครอล การแมป การค้นหา งานตามกำหนดเวลา และเหตุการณ์ระบบ
- การส่งที่ปลอดภัย: ตรวจสอบลายเซ็น HMAC-SHA256
- ลองใหม่อัตโนมัติ: กลไก retry แบบ exponential backoff
- ติดตามการส่ง: ประวัติการส่ง webhook ครบถ้วน
- กรองขอบเขต: สมัครทุกเหตุการณ์หรือเฉพาะงาน
- หัวข้อกำหนดเอง: เพิ่ม HTTP header ในการคำขอ webhook
- ป้องกัน IP ส่วนตัว: ป้องกัน SSRF ในตัว
เอนด์พอยต์ API
POST /v1/webhooks # สร้างการสมัคร webhook
GET /v1/webhooks # รายการ webhooks ทั้งหมด
GET /v1/webhooks/:webhookId # รายละเอียด webhook
PUT /v1/webhooks/:webhookId # อัปเดต webhook
DELETE /v1/webhooks/:webhookId # ลบ webhook
GET /v1/webhooks/:webhookId/deliveries # ประวัติการส่ง
POST /v1/webhooks/:webhookId/test # ส่ง webhook ทดสอบ
PUT /v1/webhooks/:webhookId/activate # เปิดใช้งาน webhook
PUT /v1/webhooks/:webhookId/deactivate # ปิดใช้งาน webhook
POST /v1/webhooks/:webhookId/deliveries/:deliveryId/replay # เล่นซ้ำการส่งที่ล้มเหลว
GET /v1/webhook-events # รายการเหตุการณ์ที่รองรับเหตุการณ์ที่รองรับ
เหตุการณ์งาน (Job)
| Event | คำอธิบาย | เมื่อเกิด |
|---|---|---|
scrape.created | สร้างงาน scrape | งาน scrape ใหม่ถูกจัดคิว |
scrape.started | เริ่มงาน scrape | งานเริ่มดำเนินการ |
scrape.completed | งาน scrape เสร็จ | งานสำเร็จ |
scrape.failed | งาน scrape ล้มเหลว | งานพบข้อผิดพลาด |
scrape.cancelled | ยกเลิกงาน scrape | ยกเลิกด้วยมือ |
crawl.created | สร้างงาน crawl | งาน crawl ใหม่ถูกจัดคิว |
crawl.started | เริ่มงาน crawl | งานเริ่มดำเนินการ |
crawl.completed | งาน crawl เสร็จ | งานสำเร็จ |
crawl.failed | งาน crawl ล้มเหลว | งานพบข้อผิดพลาด |
crawl.cancelled | ยกเลิกงาน crawl | ยกเลิกด้วยมือ |
เหตุการณ์งานตามกำหนดเวลา
| Event | คำอธิบาย | เมื่อเกิด |
|---|---|---|
task.executed | รันงานแล้ว | งานตามกำหนดเวลารัน |
task.failed | งานล้มเหลว | งานตามกำหนดเวลาล้มเหลว |
task.paused | งานหยุดชั่วคราว | งานถูกหยุด |
task.resumed | งานดำเนินต่อ | งานกลับมารัน |
เหตุการณ์การค้นหา
| Event | คำอธิบาย | เมื่อเกิด |
|---|---|---|
search.created | สร้างงานค้นหา | งานค้นหาใหม่ถูกจัดคิว |
search.started | เริ่มงานค้นหา | งานเริ่มดำเนินการ |
search.completed | งานค้นหาเสร็จ | งานสำเร็จ |
search.failed | งานค้นหาล้มเหลว | งานพบข้อผิดพลาด |
เหตุการณ์ Map
| Event | คำอธิบาย | เมื่อเกิด |
|---|---|---|
map.created | สร้างงาน map | งาน map ใหม่ถูกจัดคิว |
map.started | เริ่มงาน map | งานเริ่มดำเนินการ |
map.completed | งาน map เสร็จ | งานสำเร็จ |
map.failed | งาน map ล้มเหลว | งานพบข้อผิดพลาด |
เหตุการณ์ทดสอบ
| Event | คำอธิบาย | เมื่อเกิด |
|---|---|---|
webhook.test | เหตุการณ์ทดสอบ | ส่ง webhook ทดสอบด้วยมือ |
เริ่มต้นอย่างรวดเร็ว
สร้าง Webhook
curl -X POST "https://api.anycrawl.dev/v1/webhooks" \
-H "Authorization: Bearer <your-api-key>" \
-H "Content-Type: application/json" \
-d '{
"name": "Production Notifications",
"webhook_url": "https://your-domain.com/webhooks/anycrawl",
"event_types": ["scrape.completed", "scrape.failed", "crawl.completed"],
"scope": "all",
"timeout_seconds": 10,
"max_retries": 3
}'การตอบกลับ
{
"success": true,
"data": {
"webhook_id": "webhook-uuid-here",
"secret": "a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0u1v2w3x4y5z6",
"message": "Webhook created successfully. Save the secret - it won't be shown again."
}
}สำคัญ: บันทึก secret ทันที แสดงเพียงครั้งเดียวตอนสร้างและจำเป็นสำหรับการตรวจสอบลายเซ็น
พารามิเตอร์คำขอ
การตั้งค่า Webhook
| พารามิเตอร์ | ชนิด | จำเป็น | ค่าเริ่มต้น | คำอธิบาย |
|---|---|---|---|---|
name | string | ใช่ | - | ชื่อ webhook (1–255 ตัวอักษร) |
description | string | ไม่ | - | คำอธิบาย webhook |
webhook_url | string | ใช่ | - | URL เอนด์พอยต์ของคุณ (แนะนำ HTTPS) |
event_types | string[] | ใช่ | - | อาร์เรย์ชนิดเหตุการณ์ที่สมัคร |
scope | string | ไม่ | "all" | ขอบเขต: "all" หรือ "specific" |
specific_task_ids | string[] | ไม่ | - | ID งาน (จำเป็นเมื่อ scope เป็น "specific") |
การตั้งค่าการส่ง
| พารามิเตอร์ | ชนิด | จำเป็น | ค่าเริ่มต้น | คำอธิบาย |
|---|---|---|---|---|
timeout_seconds | number | ไม่ | 10 | Timeout คำขอ (1–60 วินาที) |
max_retries | number | ไม่ | 3 | จำนวนครั้งลองใหม่สูงสุด (0–10) |
retry_backoff_multiplier | number | ไม่ | 2 | ตัวคูณ backoff (1–10) |
custom_headers | object | ไม่ | - | HTTP header กำหนดเอง |
Webhook จะถูกปิดอัตโนมัติหลังล้มเหลวต่อเนื่อง 10 ครั้ง เพื่อป้องกันการ retry เกิน คุณเปิดใช้งานใหม่ด้วยมือหลังแก้ปัญหาได้
เมตadata
| พารามิเตอร์ | ชนิด | จำเป็น | ค่าเริ่มต้น | คำอธิบาย |
|---|---|---|---|---|
tags | string[] | ไม่ | - | แท็กจัดกลุ่ม |
metadata | object | ไม่ | - | เมตadata กำหนดเอง |
รูปแบบเพย์โหลด Webhook
HTTP Headers
ทุกคำขอ webhook มีหัวข้อเหล่านี้:
Content-Type: application/json
X-AnyCrawl-Signature: sha256=abc123...
X-Webhook-Event: scrape.completed
X-Webhook-Delivery-Id: delivery-uuid-1
X-Webhook-Timestamp: 2026-01-27T10:00:00.000Zตัวอย่างเพย์โหลด
scrape.completed
{
"job_id": "job-uuid-1",
"status": "completed",
"url": "https://example.com",
"total": 10,
"completed": 10,
"failed": 0,
"credits_used": 5,
"created_at": "2026-01-27T09:00:00.000Z",
"completed_at": "2026-01-27T10:00:00.000Z"
}scrape.failed
{
"job_id": "job-uuid-1",
"status": "failed",
"url": "https://example.com",
"error_message": "Connection timeout",
"credits_used": 3,
"created_at": "2026-01-27T09:00:00.000Z",
"completed_at": "2026-01-27T10:00:00.000Z"
}task.executed
{
"task_id": "task-uuid-1",
"task_name": "Daily News Scrape",
"execution_id": "exec-uuid-1",
"execution_number": 45,
"status": "completed",
"job_id": "job-uuid-1",
"credits_used": 5,
"scheduled_for": "2026-01-27T09:00:00.000Z",
"completed_at": "2026-01-27T09:02:15.000Z"
}การตรวจสอบลายเซ็น
ทำไมต้องตรวจ?
การตรวจลายเซ็นยืนยันว่าคำขอ webhook มาจาก AnyCrawl จริงและไม่ถูกแก้ไข ป้องกันคำขออันตราย
อัลกอริทึมการตรวจ
AnyCrawl ใช้ HMAC-SHA256 ลงนามเพย์โหลด:
signature = HMAC-SHA256(payload, webhook_secret)
header_value = "sha256=" + hex(signature)ตัวอย่างการใช้งาน
Node.js / Express
const crypto = require('crypto');
const express = require('express');
function verifyWebhookSignature(payload, signature, secret) {
const hmac = crypto.createHmac('sha256', secret);
hmac.update(JSON.stringify(payload));
const expectedSignature = `sha256=${hmac.digest('hex')}`;
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expectedSignature)
);
}
const app = express();
app.use(express.json());
app.post('/webhooks/anycrawl', (req, res) => {
const signature = req.headers['x-anycrawl-signature'];
const secret = process.env.WEBHOOK_SECRET;
// Verify signature
if (!verifyWebhookSignature(req.body, signature, secret)) {
return res.status(401).json({ error: 'Invalid signature' });
}
// Extract event info
const eventType = req.headers['x-webhook-event'];
const deliveryId = req.headers['x-webhook-delivery-id'];
console.log(`Received event: ${eventType}`);
console.log(`Delivery ID: ${deliveryId}`);
console.log('Payload:', req.body);
// Respond quickly (< 5 seconds recommended)
res.status(200).json({ received: true });
// Process asynchronously
processWebhookAsync(eventType, req.body).catch(console.error);
});
app.listen(3000);Python / Flask
import hmac
import hashlib
import json
from flask import Flask, request, jsonify
app = Flask(__name__)
WEBHOOK_SECRET = 'your-webhook-secret-here'
def verify_webhook_signature(payload, signature, secret):
expected_signature = 'sha256=' + hmac.new(
secret.encode('utf-8'),
json.dumps(payload).encode('utf-8'),
hashlib.sha256
).hexdigest()
return hmac.compare_digest(signature, expected_signature)
@app.route('/webhooks/anycrawl', methods=['POST'])
def webhook_handler():
signature = request.headers.get('X-AnyCrawl-Signature')
payload = request.get_json()
# Verify signature
if not verify_webhook_signature(payload, signature, WEBHOOK_SECRET):
return jsonify({'error': 'Invalid signature'}), 401
# Extract event info
event_type = request.headers.get('X-Webhook-Event')
delivery_id = request.headers.get('X-Webhook-Delivery-Id')
print(f'Received event: {event_type}')
print(f'Delivery ID: {delivery_id}')
print(f'Payload: {payload}')
# Respond quickly
return jsonify({'received': True}), 200
if __name__ == '__main__':
app.run(port=3000)Go
package main
import (
"crypto/hmac"
"crypto/sha256"
"encoding/hex"
"encoding/json"
"fmt"
"io"
"net/http"
"os"
)
func verifyWebhookSignature(payload []byte, signature, secret string) bool {
mac := hmac.New(sha256.New, []byte(secret))
mac.Write(payload)
expectedSignature := "sha256=" + hex.EncodeToString(mac.Sum(nil))
return hmac.Equal([]byte(signature), []byte(expectedSignature))
}
func webhookHandler(w http.ResponseWriter, r *http.Request) {
signature := r.Header.Get("X-AnyCrawl-Signature")
eventType := r.Header.Get("X-Webhook-Event")
secret := os.Getenv("WEBHOOK_SECRET")
body, err := io.ReadAll(r.Body)
if err != nil {
http.Error(w, "Error reading body", http.StatusBadRequest)
return
}
if !verifyWebhookSignature(body, signature, secret) {
http.Error(w, "Invalid signature", http.StatusUnauthorized)
return
}
var payload map[string]interface{}
if err := json.Unmarshal(body, &payload); err != nil {
http.Error(w, "Invalid JSON", http.StatusBadRequest)
return
}
fmt.Printf("Received event: %s\n", eventType)
fmt.Printf("Payload: %+v\n", payload)
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(map[string]bool{"received": true})
}
func main() {
http.HandleFunc("/webhooks/anycrawl", webhookHandler)
http.ListenAndServe(":3000", nil)
}การจัดการ Webhooks
รายการ Webhooks ทั้งหมด
curl -X GET "https://api.anycrawl.dev/v1/webhooks" \
-H "Authorization: Bearer <your-api-key>"การตอบกลับ
{
"success": true,
"data": [
{
"uuid": "webhook-uuid-1",
"name": "Production Notifications",
"webhook_url": "https://your-domain.com/webhooks/anycrawl",
"webhook_secret": "***hidden***",
"event_types": ["scrape.completed", "scrape.failed"],
"scope": "all",
"is_active": true,
"consecutive_failures": 0,
"total_deliveries": 145,
"successful_deliveries": 142,
"failed_deliveries": 3,
"last_success_at": "2026-01-27T10:00:00.000Z",
"last_failure_at": "2026-01-26T15:30:00.000Z",
"created_at": "2026-01-01T00:00:00.000Z"
}
]
}webhook_secret ถูกซ่อนในมุมมองรายการและรายละเอียดเสมอเพื่อความปลอดภัย
อัปเดต Webhook
curl -X PUT "https://api.anycrawl.dev/v1/webhooks/:webhookId" \
-H "Authorization: Bearer <your-api-key>" \
-H "Content-Type: application/json" \
-d '{
"event_types": ["scrape.completed", "scrape.failed", "crawl.completed"]
}'ไม่สามารถอัปเดต webhook secret ได้ หากต้องการเปลี่ยน ให้ลบแล้วสร้าง webhook ใหม่
ทดสอบ Webhooks
ส่งเหตุการณ์ทดสอบเพื่อตรวจการตั้งค่า:
curl -X POST "https://api.anycrawl.dev/v1/webhooks/:webhookId/test" \
-H "Authorization: Bearer <your-api-key>"เพย์โหลดทดสอบ:
{
"message": "This is a test webhook from AnyCrawl",
"timestamp": "2026-01-27T10:00:00.000Z",
"webhook_id": "webhook-uuid-1"
}ปิด/เปิดใช้งาน Webhook
curl -X PUT "https://api.anycrawl.dev/v1/webhooks/:webhookId/deactivate" \
-H "Authorization: Bearer <your-api-key>"ลบ Webhook
curl -X DELETE "https://api.anycrawl.dev/v1/webhooks/:webhookId" \
-H "Authorization: Bearer <your-api-key>"Deleting a webhook also deletes all its delivery history.
เล่นซ้ำการส่งที่ล้มเหลว
ลองส่งใหม่ด้วยมือสำหรับการส่งที่ล้มเหลว:
curl -X POST "https://api.anycrawl.dev/v1/webhooks/:webhookId/deliveries/:deliveryId/replay" \
-H "Authorization: Bearer <your-api-key>"การตอบกลับ:
{
"success": true,
"message": "Delivery replayed successfully",
"data": {
"delivery_id": "delivery-uuid-1",
"status": "pending"
}
}การเล่นซ้ำสร้างความพยายามส่งใหม่ด้วยเพย์โหลดเดิม มีประโยชน์หลังแก้ปัญหาเอนด์พอยต์
ประวัติการส่ง
ดูรายการการส่ง
curl -X GET "https://api.anycrawl.dev/v1/webhooks/:webhookId/deliveries?limit=20" \
-H "Authorization: Bearer <your-api-key>"พารามิเตอร์ Query
| พารามิเตอร์ | ชนิด | ค่าเริ่มต้น | คำอธิบาย |
|---|---|---|---|
limit | number | 100 | จำนวนการส่งที่คืน |
offset | number | 0 | จำนวนการส่งที่ข้าม |
status | string | - | กรองตามสถานะ: delivered, failed, retrying |
from | string | - | วันเริ่ม (ISO 8601) |
to | string | - | วันสิ้น (ISO 8601) |
การตอบกลับ
{
"success": true,
"data": [
{
"uuid": "delivery-uuid-1",
"webhookSubscriptionUuid": "webhook-uuid-1",
"eventType": "scrape.completed",
"status": "delivered",
"attempt_number": 1,
"request_url": "https://your-domain.com/webhooks/anycrawl",
"request_method": "POST",
"response_status": 200,
"response_duration_ms": 125,
"created_at": "2026-01-27T10:00:00.000Z",
"delivered_at": "2026-01-27T10:00:00.125Z"
},
{
"uuid": "delivery-uuid-2",
"status": "failed",
"attempt_number": 3,
"error_message": "Connection timeout",
"error_code": "ETIMEDOUT",
"created_at": "2026-01-27T09:00:00.000Z"
}
],
"meta": {
"limit": 20,
"offset": 0,
"filters": {
"status": null,
"from": null,
"to": null
}
}
}กลไกการลองใหม่
เมื่อไรมีลองใหม่
Webhook จะลองใหม่เมื่อ:
- รหัสสถานะ HTTP ไม่ใช่ 2xx
- timeout การเชื่อมต่อ
- ข้อผิดพลาดเครือข่าย
ตารางการลองใหม่
ด้วยค่าเริ่มต้น (max_retries: 3, retry_backoff_multiplier: 2):
| Attempt | Delay | Time After Initial |
|---|---|---|
| 1st retry | 1 minute | 1 minute |
| 2nd retry | 2 minutes | 3 minutes |
| 3rd retry | 4 minutes | 7 minutes |
สูตรดีเลย์: backoff_multiplier ^ (attempt - 1) × 1 minute
การปิดอัตโนมัติ
Webhook จะถูกปิดหลังล้มเหลวต่อเนื่อง 10 ครั้ง เพื่อป้องกันการ retry เกิน
เปิดใช้งานใหม่:
curl -X PUT "https://api.anycrawl.dev/v1/webhooks/:webhookId/activate" \
-H "Authorization: Bearer <your-api-key>"การกรองขอบเขต
เหตุการณ์ทั้งหมด (scope: "all")
รับการแจ้งเตือนสำหรับทุกเหตุการณ์ของชนิดที่สมัคร:
{
"scope": "all",
"event_types": ["scrape.completed", "crawl.completed"]
}เฉพาะงาน (scope: "specific")
รับเฉพาะงานตามกำหนดเวลาที่ระบุ:
{
"scope": "specific",
"specific_task_ids": ["task-uuid-1", "task-uuid-2"],
"event_types": ["task.executed", "task.failed"]
}การป้องกัน IP ส่วนตัว
พฤติกรรมเริ่มต้น
AnyCrawl บล็อกการส่ง webhook ไปยัง IP ส่วนตัว:
10.0.0.0/8172.16.0.0/12192.168.0.0/16169.254.0.0/16(link-local)127.0.0.1/localhost- IPv6 private addresses
อนุญาต Webhook ในเครื่อง (ทดสอบเท่านั้น)
สำหรับพัฒนาในเครื่อง ตั้งค่า:
ALLOW_LOCAL_WEBHOOKS=trueห้ามเปิดใน production มีความเสี่ยงด้านความปลอดภัยร้ายแรง
แนวทางปฏิบัติที่ดี
1. ตอบกลับเร็ว
คืนรหัสสถานะ 2xx ภายใน 5 วินาที:
app.post('/webhook', async (req, res) => {
// Verify signature
if (!verifySignature(req.body, req.headers['x-anycrawl-signature'])) {
return res.status(401).send('Invalid signature');
}
// Quick acknowledgment
res.status(200).json({ received: true });
// Process asynchronously
queue.add('process-webhook', req.body);
});2. ทำให้ idempotent
ใช้ X-Webhook-Delivery-Id ป้องกันการประมวลผลซ้ำ:
const processedDeliveries = new Set();
app.post('/webhook', (req, res) => {
const deliveryId = req.headers['x-webhook-delivery-id'];
if (processedDeliveries.has(deliveryId)) {
return res.status(200).json({ received: true, duplicate: true });
}
processedDeliveries.add(deliveryId);
// Process event...
res.status(200).json({ received: true });
});3. คืนรหัสสถานะที่เหมาะสม
| Status Code | คำอธิบาย | พฤติกรรม AnyCrawl |
|---|---|---|
| 200-299 | สำเร็จ | ไม่ลองใหม่ |
| 400-499 | ข้อผิดพลาดฝั่งไคลเอนต์ | ไม่ลองใหม่ (บันทึกว่าล้มเหลว) |
| 500-599 | ข้อผิดพลาดฝั่งเซิร์ฟเวอร์ | ลองใหม่แบบ backoff |
| Timeout | timeout เครือข่าย | ลองใหม่แบบ backoff |
4. บันทึกกิจกรรม Webhook
app.post('/webhook', (req, res) => {
const deliveryId = req.headers['x-webhook-delivery-id'];
const eventType = req.headers['x-webhook-event'];
logger.info('Webhook received', {
deliveryId,
eventType,
timestamp: req.headers['x-webhook-timestamp']
});
try {
processWebhook(req.body, eventType);
logger.info('Webhook processed', { deliveryId });
res.status(200).json({ received: true });
} catch (error) {
logger.error('Webhook failed', {
deliveryId,
error: error.message
});
res.status(500).json({ error: 'Processing failed' });
}
});5. เช็กลิสต์ความปลอดภัย
- ✅ ตรวจลายเซ็นเสมอ
- ✅ ใช้ HTTPS ใน production
- ✅ อย่าเปิดเผยความลับใน URL
- ✅ จำกัดอัตราเมื่อเหมาะสม
- ✅ มอนิเตอร์ความผิดปกติ
- ✅ ตรวจโครงสร้างเพย์โหลด
กรณีใช้งานทั่วไป
แจ้งเตือน Slack
ส่งผลการดึงข้อมูลไป Slack:
app.post('/webhooks/anycrawl', async (req, res) => {
const { job_id, status, url } = req.body;
await fetch(process.env.SLACK_WEBHOOK_URL, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
text: `Job ${status}: ${url}\nJob ID: ${job_id}`
})
});
res.status(200).json({ received: true });
});แจ้งเตือนอีเมล
ส่งอีเมลเมื่อล้มเหลว:
app.post('/webhooks/anycrawl', async (req, res) => {
const eventType = req.headers['x-webhook-event'];
if (eventType.endsWith('.failed')) {
await sendEmail({
to: 'admin@example.com',
subject: 'AnyCrawl Job Failed',
body: JSON.stringify(req.body, null, 2)
});
}
res.status(200).json({ received: true });
});บันทึกลงฐานข้อมูล
เก็บเหตุการณ์ webhook ในฐานข้อมูล:
app.post('/webhooks/anycrawl', async (req, res) => {
const eventType = req.headers['x-webhook-event'];
const deliveryId = req.headers['x-webhook-delivery-id'];
await db.webhookEvents.create({
deliveryId,
eventType,
payload: req.body,
receivedAt: new Date()
});
res.status(200).json({ received: true });
});แก้ปัญหา
Webhook ไม่ได้รับเหตุการณ์
ตรวจสอบ:
- webhook active? (
is_active: true) - ตั้งชนิดเหตุการณ์ถูกต้อง?
- URL เข้าถึงจากอินเทอร์เน็ตได้?
- ถูกบล็อกโดยการป้องกัน IP ส่วนตัว?
- ขอบเขต (all กับ specific)
การตรวจลายเซ็นล้มเหลว
ปัญหาทั่วไป:
- secret ผิด (ใช้ค่าตอนสร้าง webhook)
- ไม่ stringify เพย์โหลดก่อนแฮช
- JSON มีช่องว่างหรือรูปแบบเกิน
- อัลกอริทึม HMAC ผิด (ต้อง SHA-256)
อัตราล้มเหลวสูง
แนวทาง:
- เอนด์พอยต์ตอบภายใน 5 วินาที
- คืนรหัสสถานะที่เหมาะสม
- ดูข้อความข้อผิดพลาดในประวัติการส่ง
- ทดสอบในเครื่องด้วย ngrok หรือเครื่องมือคล้ายกัน
Webhook ถูกปิดอัตโนมัติ
สาเหตุ: ล้มเหลวต่อเนื่อง 10 ครั้ง
แนวทาง:
- แก้สาเหตุ (เอนด์พอยต์ การตรวจลายเซ็น ฯลฯ)
- ทดสอบด้วยเอนด์พอยต์ทดสอบ
- เปิดใช้งาน webhook ใหม่:
curl -X PUT "https://api.anycrawl.dev/v1/webhooks/:webhookId/activate" \
-H "Authorization: Bearer <your-api-key>"เครื่องมือดีบัก
เครื่องมือทดสอบ
- webhook.site — ตรวจคำขอ webhook
- requestbin.com — ตรวจคำขอ
- ngrok — ท่อนเครื่องในเครื่องสำหรับทดสอบ
พัฒนาในเครื่อง
ใช้ ngrok เพื่อเปิดเซิร์ฟเวอร์ในเครื่อง:
ngrok http 3000จากนั้นใช้ URL ของ ngrok เป็น webhook URL:
https://abc123.ngrok.io/webhooks/anycrawlข้อจำกัด
| Item | Limit |
|---|---|
| ความยาวชื่อ webhook | 1–255 ตัวอักษร |
| URL webhook | แนะนำ HTTPS (production) |
| Timeout | 1–60 วินาที |
| ลองใหม่สูงสุด | 0–10 |
| ขนาดเพย์โหลด | สูงสุด 1MB |
| Header กำหนดเอง | สูงสุด 20 |
| ชนิดเหตุการณ์ต่อ webhook | ไม่จำกัด |
เอกสารที่เกี่ยวข้อง
- งานตามกำหนดเวลา — ระบบอัตโนมัติงานเกิดซ้ำ
- Scrape API — เอนด์พอยต์การดึงข้อมูล
- Crawl API — เอนด์พอยต์การครอล