AnyCrawl

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

พารามิเตอร์ชนิดจำเป็นค่าเริ่มต้นคำอธิบาย
namestringใช่-ชื่อ webhook (1–255 ตัวอักษร)
descriptionstringไม่-คำอธิบาย webhook
webhook_urlstringใช่-URL เอนด์พอยต์ของคุณ (แนะนำ HTTPS)
event_typesstring[]ใช่-อาร์เรย์ชนิดเหตุการณ์ที่สมัคร
scopestringไม่"all"ขอบเขต: "all" หรือ "specific"
specific_task_idsstring[]ไม่-ID งาน (จำเป็นเมื่อ scope เป็น "specific")

การตั้งค่าการส่ง

พารามิเตอร์ชนิดจำเป็นค่าเริ่มต้นคำอธิบาย
timeout_secondsnumberไม่10Timeout คำขอ (1–60 วินาที)
max_retriesnumberไม่3จำนวนครั้งลองใหม่สูงสุด (0–10)
retry_backoff_multipliernumberไม่2ตัวคูณ backoff (1–10)
custom_headersobjectไม่-HTTP header กำหนดเอง

Webhook จะถูกปิดอัตโนมัติหลังล้มเหลวต่อเนื่อง 10 ครั้ง เพื่อป้องกันการ retry เกิน คุณเปิดใช้งานใหม่ด้วยมือหลังแก้ปัญหาได้

เมตadata

พารามิเตอร์ชนิดจำเป็นค่าเริ่มต้นคำอธิบาย
tagsstring[]ไม่-แท็กจัดกลุ่ม
metadataobjectไม่-เมต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

พารามิเตอร์ชนิดค่าเริ่มต้นคำอธิบาย
limitnumber100จำนวนการส่งที่คืน
offsetnumber0จำนวนการส่งที่ข้าม
statusstring-กรองตามสถานะ: delivered, failed, retrying
fromstring-วันเริ่ม (ISO 8601)
tostring-วันสิ้น (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):

AttemptDelayTime After Initial
1st retry1 minute1 minute
2nd retry2 minutes3 minutes
3rd retry4 minutes7 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/8
  • 172.16.0.0/12
  • 192.168.0.0/16
  • 169.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
Timeouttimeout เครือข่ายลองใหม่แบบ 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 ครั้ง

แนวทาง:

  1. แก้สาเหตุ (เอนด์พอยต์ การตรวจลายเซ็น ฯลฯ)
  2. ทดสอบด้วยเอนด์พอยต์ทดสอบ
  3. เปิดใช้งาน 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

ข้อจำกัด

ItemLimit
ความยาวชื่อ webhook1–255 ตัวอักษร
URL webhookแนะนำ HTTPS (production)
Timeout1–60 วินาที
ลองใหม่สูงสุด0–10
ขนาดเพย์โหลดสูงสุด 1MB
Header กำหนดเองสูงสุด 20
ชนิดเหตุการณ์ต่อ webhookไม่จำกัด

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

สารบัญ

บทนำคุณสมบัติหลักเอนด์พอยต์ APIเหตุการณ์ที่รองรับเหตุการณ์งาน (Job)เหตุการณ์งานตามกำหนดเวลาเหตุการณ์การค้นหาเหตุการณ์ Mapเหตุการณ์ทดสอบเริ่มต้นอย่างรวดเร็วสร้าง Webhookการตอบกลับพารามิเตอร์คำขอการตั้งค่า Webhookการตั้งค่าการส่งเมตadataรูปแบบเพย์โหลด WebhookHTTP Headersตัวอย่างเพย์โหลดscrape.completedscrape.failedtask.executedการตรวจสอบลายเซ็นทำไมต้องตรวจ?อัลกอริทึมการตรวจตัวอย่างการใช้งานNode.js / ExpressPython / FlaskGoการจัดการ Webhooksรายการ Webhooks ทั้งหมดการตอบกลับอัปเดต Webhookทดสอบ Webhooksปิด/เปิดใช้งาน Webhookลบ Webhookเล่นซ้ำการส่งที่ล้มเหลวประวัติการส่งดูรายการการส่งพารามิเตอร์ Queryการตอบกลับกลไกการลองใหม่เมื่อไรมีลองใหม่ตารางการลองใหม่การปิดอัตโนมัติการกรองขอบเขตเหตุการณ์ทั้งหมด (scope: "all")เฉพาะงาน (scope: "specific")การป้องกัน IP ส่วนตัวพฤติกรรมเริ่มต้นอนุญาต Webhook ในเครื่อง (ทดสอบเท่านั้น)แนวทางปฏิบัติที่ดี1. ตอบกลับเร็ว2. ทำให้ idempotent3. คืนรหัสสถานะที่เหมาะสม4. บันทึกกิจกรรม Webhook5. เช็กลิสต์ความปลอดภัยกรณีใช้งานทั่วไปแจ้งเตือน Slackแจ้งเตือนอีเมลบันทึกลงฐานข้อมูลแก้ปัญหาWebhook ไม่ได้รับเหตุการณ์การตรวจลายเซ็นล้มเหลวอัตราล้มเหลวสูงWebhook ถูกปิดอัตโนมัติเครื่องมือดีบักเครื่องมือทดสอบพัฒนาในเครื่องข้อจำกัดเอกสารที่เกี่ยวข้อง