การทดสอบเวบฮุก
คำแนะนำที่สมบูรณ์ สำหรับการทดสอบการจัดส่งเวบฮุก, การใช้งานตัวจัดการเวบฮุก, การแก้ไขปัญหาเหตุการณ์เวบฮุก และการตั้งค่าการทดสอบเวบฮุกแบบอัตโนมัติสำหรับการผสานรวม Omise ของคุณ
ภาพรวม
เวบฮุกเป็นการเรียกกลับ HTTP ที่แจ้งให้แอปพลิเคชันของคุณทราบเกี่ยวกับเหตุการณ์การชำระเงินแบบเรียลไทม์ การทดสอบเวบฮุกอย่างเหมาะสมจะช่วยให้มั่นใจได้ว่าแอปพลิเคชันของคุณจัดการเหตุการณ์การชำระเงินอย่างถูกต้อง ประมวลผลเหตุการณ์ที่ซ้ำกันอย่างปลอดภัย และกู้คืนจากความล้มเหลวได้อย่างสง่างาม
เหตุใดจึงต้องทดสอบเวบฮุก
- การจัดการเหตุการณ์: ตรวจสอบว่าเหตุการณ์การชำระเงินทั้งหมดได้รับการประมวลผลอย่างถูกต้อง
- ความเป็นปัญหาเดียวกัน: จัดการการจัดส่งเวบฮุกที่ซ้ำกันอย่างปลอดภัย
- ความปลอดภัย: ตรวจสอบลายเซ็นเวบฮุกและป้องกันการปลอมแปลง
- ความน่าเชื่อถือ: จัดการความล้มเหลวในการจัดส่งและปัญหาเครือข่าย
- ประสิทธิภาพ: ประมวลผลเวบฮุกแบบไม่ซิงโครนัสโดยไม่มีการหมดเวลา
- การแก้ไขปัญหา: การระบุและแก้ไขปัญหาการผสานรวมอย่างรวดเร็ว
กลยุทธ์การทดสอบเวบฮุก
- การทดสอบในเครื่อง: ใช้ ngrok เพื่อทดสอบเวบฮุกบนเครื่องท้องถิ่นของคุณ
- กา รทดสอบด้วย Mock: ใช้บริการการทดสอบเวบฮุกสำหรับการทดสอบอย่างรวดเร็ว
- การทดสอบแบบอัตโนมัติ: เขียนการทดสอบสำหรับตัวจัดการเวบฮุกของคุณ
- การทดสอบการผสานรวม: ทดสอบลำดับการไหลของเวบฮุกแบบปลายต่อปลาย
- การตรวจสอบการผลิต: ตรวจสอบการจัดส่งและการประมวลผลเวบฮุก
การตั้งค่าการทดสอบเวบฮุก
การกำหนดค่าจุดสิ้นสุดเวบฮุก
ก่อนอื่น, ให้กำหนดค่าจุดสิ้นสุดเวบฮุกของคุณในแดชบอร์ด Omise:
- ไปที่ การตั้งค่า > เวบฮุก
- คลิก เพิ่มจุดสิ้นสุดเวบฮุก
- ป้อน URL เวบฮุกของคุณ
- เลือกเหตุการณ์เพื่อรับ
- บันทึกการกำหนดค่า
สำหรับการพัฒนาในเครื่อง, ใช้ ngrok เพื่อสร้าง URL สาธารณะ
ความเข้าใจในเหตุการณ์เวบฮุก
Omise ส่งเวบฮุกสำหรับเหตุการณ์เหล่านี้:
| เหตุการณ์ | คำอธิบาย |
|---|---|
charge.create | ประจำที่สร้าง |
charge.complete | ประจำสำเร็จแล้ว |
charge.expire | ประจำหมดอายุโดยไม่มีการชำระเงิน |
refund.create | การคืนเงินสร้าง |
transfer.create | การโอนสร้าง |
transfer.pay | การโอนออก |
customer.create | ลูกค้าสร้าง |
customer.update | ลูกค้าอัปเดต |
customer.destroy | ลูกค้าลบ |
card.create | บัตรสร้าง |
card.update | บัตรอัปเดต |
card.destroy | บัตรลบ |
dispute.create | ข้อพิพาทสร้าง |
dispute.update | ข้อพิพาทอัปเดต |
การทดสอบด้วย ngrok
การติดตั้ง ngrok
ngrok สร้างอุโมงค์ที่ปลอดภัยสู่ localhost ของคุณ, ช่วยให้ Omise สามารถส่งเวบฮุกไปยังเครื่องพัฒนาของคุณ
การติดตั้ง:
# macOS (Homebrew)
brew install ngrok
# Windows (Chocolatey)
choco install ngrok
# Linux (โหลดตรง)
wget https://bin.equinox.io/c/4VmDzA7iaHb/ngrok-stable-linux-amd64.zip
unzip ngrok-stable-linux-amd64.zip
sudo mv ngrok /usr/local/bin/
# ตรวจสอบการติดตั้ง
ngrok version
ลงทะเบียนและตรวจสอบสิทธิ์:
# ลงทะเบียนที่ https://dashboard.ngrok.com/signup
# รับโทเค็นการตรวจสอบสิทธิ์จาก https://dashboard.ngrok.com/get-started/your-authtoken
ngrok config add-authtoken YOUR_AUTH_TOKEN
การใช้ ngrok สำหรับการทดสอบเวบฮุก
เริ่มต้นอุโมงค์ ngrok:
# ส่งต่อไปยังพอร์ต 3000 ในเครื่อง
ngrok http 3000
# ด้วยโดเมนย่อยที่กำหนดเอง (แผนที่จ่ายเงิน)
ngrok http -subdomain=myapp 3000
# ด้วยภูมิภาคที่กำหนดเอง
ngrok http -region=ap 3000
ผลลัพธ์ ngrok:
Session Status online
Account your@email.com
Version 3.0.0
Region Asia Pacific (ap)
Web Interface http://127.0.0.1:4040
Forwarding https://abc123.ap.ngrok.io -> http://localhost:3000
ใช้ URL ส่งต่อในแดชบอร์ด Omise:
Webhook URL: https://abc123.ap.ngrok.io/webhooks
การทดสอบด้วย Webhook.site
การใช้ Webhook.site
Webhook.site มี URL ชั่วคราวสำหรับการทดสอบเวบฮุกโดยไม่ต้องเขียนโค้ด
ขั้นตอน:
- ไปที่ https://webhook.site
- คัดลอก URL ที่ไม่ซ้ำกันของคุณ (เช่น
https://webhook.site/abc-123) - เพิ่ม URL นี้เข้าไปในเวบฮุก Omise Dashboard
- เรียกใช้เหตุการณ์ทดสอบใน Omise
- ดูคำขอแบบเรียลไทม์บน webhook.site
ฟีเจอร์:
- ดู headers, body และ query parameters ของคำขอ
- ตรวจสอบสถานะการตอบสนองแ ละ body
- แก้ไขและปรับแต่งการตอบสนอง
- ส่งออกข้อมูลคำขอ
- แชร์ URL เวบฮุกกับทีม
การทดสอบแบบอัตโนมัติ
การทดสอบด้วย Jest (JavaScript/Node.js)
// webhook.test.js - Jest tests สำหรับตัวจัดการเวบฮุก
const request = require('supertest');
const crypto = require('crypto');
const app = require('./app'); // แอป Express ของคุณ
describe('Webhook Handler', () => {
const SECRET_KEY = 'skey_test_xxxxxxxxxx';
function generateSignature(payload) {
return crypto
.createHmac('sha256', SECRET_KEY)
.update(JSON.stringify(payload))
.digest('hex');
}
describe('POST /webhooks', () => {
test('ควรยอมรับเวบฮุกที่ถูกต้องพร้อมลายเซ็นท ี่ถูกต้อง', async () => {
const payload = {
key: 'charge.complete',
data: {
id: 'chrg_test_123',
amount: 100000,
currency: 'THB',
status: 'successful'
}
};
const signature = generateSignature(payload);
const response = await request(app)
.post('/webhooks')
.set('X-Omise-Signature', signature)
.send(payload);
expect(response.status).toBe(200);
expect(response.body).toEqual({ received: true });
});
test('ควรปฏิเสธเวบฮุกที่มีลายเซ็นไม่ถูกต้อง', async () => {
const payload = {
key: 'charge.complete',
data: {
id: 'chrg_test_123',
amount: 100000,
currency: 'THB',
status: 'successful'
}
};
const response = await request(app)
.post('/webhooks')
.set('X-Omise-Signature', 'invalid_signature')
.send(payload);
expect(response.status).toBe(401);
expect(response.body).toHaveProperty('error');
});
test('ควรจัดการเหตุการณ์ charge.complete', async () => {
const payload = {
key: 'charge.complete',
data: {
id: 'chrg_test_123',
amount: 100000,
currency: 'THB',
status: 'successful'
}
};
const signature = generateSignature(payload);
const response = await request(app)
.post('/webhooks')
.set('X-Omise-Signature', signature)
.send(payload);
expect(response.status).toBe(200);
// ตรวจสอบว่าเหตุการณ์ได้รับการประมวลผล
// ตรวจสอบฐานข้อมูล, บันทึก ฯลฯ
});
test('ควรจัดการเวบฮุกที่ซ้ำกันอย่างสมมาตร', async () => {
const payload = {
key: 'charge.complete',
data: {
id: 'chrg_test_125',
amount: 100000,
currency: 'THB',
status: 'successful'
}
};
const signature = generateSignature(payload);
// ส่งเวบฮุกเดียว กันสองครั้ง
const response1 = await request(app)
.post('/webhooks')
.set('X-Omise-Signature', signature)
.send(payload);
const response2 = await request(app)
.post('/webhooks')
.set('X-Omise-Signature', signature)
.send(payload);
expect(response1.status).toBe(200);
expect(response2.status).toBe(200);
// ตรวจสอบว่าเหตุการณ์ได้รับการประมวลผลเพียงครั้งเดียว
// ตรวจสอบฐานข้อมูลเพื่อดูบันทึกเดียว
});
});
});
การทดสอบด้วย Pytest (Python)
# test_webhooks.py - Pytest tests สำหรับตัวจัดการเวบฮุก
import pytest
import json
import hmac
import hashlib
from flask import Flask
from app import app # แอป Flask ของคุณ
@pytest.fixture
def client():
"""สร้างไคลเอนต์ทดสอบ"""
app.config['TESTING'] = True
with app.test_client() as client:
yield client
@pytest.fixture
def secret_key():
"""คีย์ลับทดสอบ"""
return 'skey_test_xxxxxxxxxx'
def generate_signature(payload, secret_key):
"""สร้างลายเซ็น HMAC สำหรับเวบฮุก"""
payload_str = json.dumps(payload)
signature = hmac.new(
secret_key.encode('utf-8'),
payload_str.encode('utf-8'),
hashlib.sha256
).hexdigest()
return signature
class TestWebhookHandler:
"""ทดสอบตัวจัดการเวบฮุก"""
def test_valid_webhook_with_correct_signature(self, client, secret_key):
"""ควรยอมรับเ วบฮุกที่ถูกต้องพร้อมลายเซ็นที่ถูกต้อง"""
payload = {
'key': 'charge.complete',
'data': {
'id': 'chrg_test_123',
'amount': 100000,
'currency': 'THB',
'status': 'successful'
}
}
signature = generate_signature(payload, secret_key)
response = client.post(
'/webhooks',
data=json.dumps(payload),
headers={
'Content-Type': 'application/json',
'X-Omise-Signature': signature
}
)
assert response.status_code == 200
assert response.json['received'] == True
def test_reject_invalid_signature(self, client):
"""ควรปฏิเสธเวบฮุกที่มีลายเซ็นไม่ถูกต้อง"""
payload = {
'key': 'charge.complete',
'data': {'id': 'chrg_test_123'}
}
response = client.post(
'/webhooks',
data=json.dumps(payload),
headers={
'Content-Type': 'application/json',
'X-Omise-Signature': 'invalid_signature'
}
)
assert response.status_code == 401
assert 'error' in response.json
def test_handle_charge_complete(self, client, secret_key):
"""ควรจัดการเหตุการณ์ charge.complete"""
payload = {
'key': 'charge.complete',
'data': {
'id': 'chrg_test_123',
'amount': 100000,
'currency': 'THB',
'status': 'successful'
}
}
signature = generate_signature(payload, secret_key)
response = client.post(
'/webhooks',
data=json.dumps(payload),
headers={
'Content-Type': 'application/json',
'X-Omise-Signature': signature
}
)
assert response.status_code == 200
# ตรวจสอบว่าเหตุการณ์ได้รับการประมวลผลอย่างถูกต้อง
# ตรวจสอบฐานข้อมูล, บันทึก ฯลฯ
@pytest.mark.parametrize('event_key,expected_status', [
('charge.complete', 200),
('charge.expire', 200),
('refund.create', 200),
('transfer.create', 200),
])
def test_handle_different_events(self, client, secret_key, event_key, expected_status):
"""ควรจัดการประเภทเหตุการณ์ที่แตกต่างกัน"""
payload = {
'key': event_key,
'data': {'id': 'test_123'}
}
signature = generate_signature(payload, secret_key)
response = client.post(
'/webhooks',
data=json.dumps(payload),
headers={
'Content-Type': 'application/json',
'X-Omise-Signature': signature
}
)
assert response.status_code == expected_status
การทดสอบด้วย RSpec (Ruby)
# spec/webhooks_spec.rb - RSpec tests สำหรับตัวจัดการเวบฮุก
require 'rails_helper'
require 'openssl'
require 'json'
RSpec.describe 'Webhooks', type: :request do
let(:secret_key) { 'skey_test_xxxxxxxxxx' }
def generate_signature(payload)
OpenSSL::HMAC.hexdigest(
OpenSSL::Digest.new('sha256'),
secret_key,
payload.to_json
)
end
describe 'POST /webhooks' do
context 'ด้วยลายเซ็นที่ถูกต้อง' do
it 'ยอมรับเวบฮุกและส่งกลับ 200' do
payload = {
key: 'charge.complete',
data: {
id: 'chrg_test_123',
amount: 100_000,
currency: 'THB',
status: 'successful'
}
}
signature = generate_signature(payload)
post '/webhooks',
params: payload.to_json,
headers: {
'Content-Type' => 'application/json',
'X-Omise-Signature' => signature
}
expect(response).to have_http_status(:ok)
expect(JSON.parse(response.body)['received']).to be true
end
end
context 'ด้วยลายเซ็นไม่ถูกต้อง' do
it 'ปฏิเสธเวบฮุกและส่งกลับ 401' do
payload = {
key: 'charge.complete',
data: { id: 'chrg_test_123' }
}
post '/webhooks',
params: payload.to_json,
headers: {
'Content-Type' => 'application/json',
'X-Omise-Signature' => 'invalid_signature'
}
expect(response).to have_http_status(:unauthorized)
end
end
context 'การจัดการเหตุการณ์ charge.complete' do
it 'ประมวลผลการทำให้ประจำเสร็จสิ้น' do
payload = {
key: 'charge.complete',
data: {
id: 'chrg_test_123',
amount: 100_000,
currency: 'THB',
status: 'successful'
}
}
signature = generate_signature(payload)
expect {
post '/webhooks',
params: payload.to_json,
headers: {
'Content-Type' => 'application/json',
'X-Omise-Signature' => signature
}
}.to change { ProcessedWebhook.count }.by(1)
expect(response).to have_http_status(:ok)
end
end
context 'การจัดการเวบฮุกที่ซ้ำกัน' do
it 'ประมวลผลเวบฮุกเพียงครั้งเดียว' do
payload = {
key: 'charge.complete',
data: {
id: 'chrg_test_125',
amount: 100_000,
currency: 'THB',
status: 'successful'
}
}
signature = generate_signature(payload)
# ส่งเวบฮุกสองครั้ง
2.times do
post '/webhooks',
params: payload.to_json,
headers: {
'Content-Type' => 'application/json',
'X-Omise-Signature' => signature
}
expect(response).to have_http_status(:ok)
end
# ตรวจสอบว่าประมวลผลเพียงครั้งเดียว
expect(ProcessedWebhook.where(event_id: payload[:data][:id]).count).to eq(1)
end
end
end
end
การผสานรวม CI/CD
GitHub Actions สำหรับการทดสอบเวบฮุก
# .github/workflows/test-webhooks.yml
name: ทดสอบเวบฮุก
on:
push:
branches: [main, develop]
pull_request:
branches: [main]
jobs:
test-webhooks:
runs-on: ubuntu-latest
services:
postgres:
image: postgres:13
env:
POSTGRES_PASSWORD: postgres
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
steps:
- uses: actions/checkout@v3
- name: ตั้งค่า Node.js
uses: actions/setup-node@v3
with:
node-version: '18'
cache: 'npm'
- name: ติดตั้งความต้องการ
run: npm ci
- name: ตั้งค่าฐานข้อมูลทดสอบ
run: npm run db:setup
env:
DATABASE_URL: postgresql://postgres:postgres@localhost:5432/test_db
- name: เรียกใช้การทดสอบเวบฮุก
run: npm test -- --testPathPattern=webhooks
env:
OMISE_SECRET_KEY: ${{ secrets.OMISE_SECRET_KEY_TEST }}
NODE_ENV: test
- name: อัปโหลดผลการทดสอบ
if: always()
uses: actions/upload-artifact@v3
with:
name: webhook-test-results
path: test-results/
แนวทางปฏิบัติที่ดี
1. ตรวจสอบลายเซ็นเ วบฮุก
ตรวจสอบลายเซ็นเวบฮุกเสมอเพื่อป้องกันการปลอมแปลง:
<?php
// PHP - การตรวจสอบลายเซ็นเวบฮุก
function verifyWebhookSignature($payload, $signature, $secretKey) {
$expectedSignature = hash_hmac('sha256', $payload, $secretKey);
// ใช้การเปรียบเทียบที่ปลอดภัยจากการกำหนดเวลา
return hash_equals($expectedSignature, $signature);
}
// การใช้งาน
$payload = file_get_contents('php://input');
$signature = $_SERVER['HTTP_X_OMISE_SIGNATURE'] ?? '';
if (!verifyWebhookSignature($payload, $signature, $secretKey)) {
http_response_code(401);
echo json_encode(['error' => 'Invalid signature']);
exit;
}
// ประมวลผลเวบฮุก
$event = json_decode($payload, true);
processWebhook($event);
http_response_code(200);
echo json_encode(['received' => true]);
?>
2. ประมวลผลเวบฮุกแบบไม่ซิงโครนัส
ตอบสนองต่อเวบฮุกอย่างรวดเร็วและประมวลผลแบบไม่ซิงโครนัส:
# Python - การประมวลผลเวบฮุกแบบไม่ซิงโครนัส
from flask import Flask, request, jsonify
import threading
import queue
app = Flask(__name__)
webhook_queue = queue.Queue()
def process_webhooks_async():
"""คนงานพื้นหลังเพื่อประมวลผลเวบฮุก"""
while True:
try:
event = webhook_queue.get()
# ประมวลผลเหตุการณ์
process_webhook_event(event)
webhook_queue.task_done()
except Exception as e:
print(f'Error processing webhook: {e}')
# เริ่มคนงานพื้นหลัง
worker_thread = threading.Thread(target=process_webhooks_async, daemon=True)
worker_thread.start()
@app.route('/webhooks', methods=['POST'])
def handle_webhook():
# ตรวจสอบลายเซ็น
if not verify_signature(request):
return jsonify({'error': 'Invalid signature'}), 401
# เข้าคิวสำหรับประมวลผล
event = request.json
webhook_queue.put(event)
# ตอบสนองทันที
return jsonify({'received': True}), 200
def process_webhook_event(event):
"""ประมวลผลเหตุการณ์เวบฮุก (ทำงานในพื้นหลัง)"""
event_key = event.get('key')
data = event.get('data', {})
try:
if event_key == 'charge.complete':
handle_charge_complete(data)
elif event_key == 'refund.create':
handle_refund_create(data)
# จัดการเหตุการณ์อื่นๆ...
except Exception as e:
print(f'Error in webhook processing: {e}')
# บันทึกข้อผิดพลาด, ส่งการแจ้งเตือน ฯลฯ
3. บันทึกเหตุการณ์เวบฮุก
บันทึกอย่างครอบคลุมเพื่อการแก้ไขปัญหา:
// JavaScript - การบันทึกเวบฮุก
const winston = require('winston');
const logger = winston.createLogger({
level: 'info',
format: winston.format.json(),
transports: [
new winston.transports.File({ filename: 'webhooks-error.log', level: 'error' }),
new winston.transports.File({ filename: 'webhooks.log' })
]
});
app.post('/webhooks', (req, res) => {
const event = req.body;
const signature = req.headers['x-omise-signature'];
// บันทึกเวบฮุกที่ได้รับ
logger.info('Webhook received', {
event_key: event.key,
event_id: event.data?.id,
timestamp: new Date().toISOString(),
signature: signature
});
try {
// ตรวจสอบลายเซ็น
if (!verifySignature(req.body, signature)) {
logger.error('Invalid webhook signature', {
event_key: event.key,
signature: signature
});
return res.status(401).json({ error: 'Invalid signature' });
}
// ประมวลผลเวบฮุก
processWebhook(event);
logger.info('Webhook processed successfully', {
event_key: event.key,
event_id: event.data?.id
});
res.json({ received: true });
} catch (error) {
logger.error('Webhook processing failed', {
event_key: event.key,
error: error.message,
stack: error.stack
});
res.status(500).json({ error: 'Processing failed' });
}
});
การแก้ไขปัญหา
ปัญหาทั่วไป
ปัญหา: เวบฮุกไม่ได้รับ
สาเหตุที่เป็นไปได้:
- URL เวบฮุกไม่ได้กำหนดค่าในแดชบอร์ด Omise
- ไฟร์วอลล์บล็อกคำขอ
- อุโมงค์ ngrok ไม่ทำงาน
- เซิร์ฟเวอร์ไม่รับฟังบนพอร์ตที่ถูกต้อง
วิธีแก้ไข:
- ตรวจสอบ URL เวบฮุกในแดชบอร์ด Omise
- ตรวจสอบบันทึกเซิร์ฟเวอร์สำหรับคำขอขาเข้า
- ทดสอบด้วย webhook.site ก่อน
- ตรวจสอบว่า ngrok ทำงานอยู่:
curl http://localhost:4040/api/tunnels
ปัญหา: การตรวจสอบลายเซ็นล้มเหลว
สาเหตุที่เป็นไปได้:
- ใช้คีย์ลับไม่ถูกต้อง
- เปรียบเทียบกับรูปแบบเพย์โหลดไม่ถูกต้อง
- ปัญหาการเข้ารหัส
วิธีแก้ไข:
// ลายเซ็นการแก้ไขข้อบกพร่อง
const receivedSignature = req.headers['x-omise-signature'];
const payload = JSON.stringify(req.body);
const secretKey = process.env.OMISE_SECRET_KEY;
const expectedSignature = crypto
.createHmac('sha256', secretKey)
.update(payload)
.digest('hex');
console.log('Received:', receivedSignature);
console.log('Expected:', expectedSignature);
console.log('Match:', receivedSignature === expectedSignature);
ปัญหา: เวบฮุกหมดเวลา
สาเหตุ: การประมวลผลใช้เวลานานเกินไป
วิธีแก้ไข: ประมวลผลแบบไม่ซิงโครนัส:
# ตอบสนองอย่างรวดเร็ว, ประมวลผลแบบไม่ซิงโครนัส
@app.route('/webhooks', methods=['POST'])
def handle_webhook():
event = request.json
# เข้าคิวสำหรับประมวลผลในพื้นหลัง
celery_app.send_task('process_webhook', args=[event])
# ตอบสนองทันที
return jsonify({'received': True}), 200
คำถามที่พบบ่อย
Omise รอตอบสนองเวบฮุกนานแค่ไหน
Omise รอ 30 วินาทีเพื่อให้จุดสิ้นสุดของคุณตอบสนอง หากไม่มีการตอบสนองภายใน 30 วินาที, เวบฮุกจะถูกทำเครื่องหมายว่าล้มเหลวและจะลองใหม่
ฉันต้องตรวจสอบลายเซ็นเวบฮุกหรือไม่
ใช่, ตรวจสอบลายเซ็นเวบฮุกเสมอเพื่อป้องกันการปลอมแปลง Omise ลงนามในเวบฮุกทั้งหมดด้วย HMAC-SHA256 โดยใช้คีย์ลับของคุณ
ฉันสามารถทดสอบเวบฮุกในโหมดทดสอบได้หรือไม่
ใช่, โหมดทดสอบส่งเวบฮุกเช่นเดียวกับการผลิต กำหนดค่าจุดสิ้นสุดเวบฮุกโหมดทดสอบแยกต่างหากในแดชบอร์ด Omise
ฉันสามารถเล่นเวบฮุกใหม่ได้หรือไม่
ใช่, คุณสามารถเล่นเวบฮุกใหม่ได้จากแดชบอร์ด Omise ไปที่ การตั้งค่า > เวบฮุก, ค้นหาเหตุการณ์ และคลิก "ส่งใหม่"
ฉันควรจัดการเวบฮุกที่ซ้ำกันอย่างไร
ใช้ ID เหตุการณ์เพื่อติดตามเหตุการณ์ที่คุณประมวลผลแล้ว เก็บ ID เหตุการณ์ที่ประมวลผลแล้วในฐานข้อมูลของคุณและข้ามการประมวลผลซ้ำ
ทรัพยากรที่เกี่ยวข้อง
- เลขบัตรทดสอบและข้อมูล - เลขบัตรทดสอบสำหรับสถานการณ์เวบฮุก
- จำลองความล้มเหลว - การทดสอบสถานการณ์ความล้มเหลวของเวบฮุก
- คำแนะนำเวบฮุก - เอกสารเวบฮุกที่สมบูรณ์
- การตรวจสอบสิทธิ์ API - การทำความเข้า ใจลายเซ็นเวบฮุก
- อ้างอิงรหัสข้อผิดพลาด - รหัสข้อผิดพลาดในการตอบสนองเวบฮุก
- แนวทางปฏิบัติที่ดี - แนวทางปฏิบัติการใช้งานเวบฮุก
ขั้นตอนถัดไป
- ตั้งค่า ngrok สำหรับการทดสอบเวบฮุกในเครื่อง
- ใช้การตรวจสอบลายเซ็น ในตัวจัดการเวบฮุกของคุณ
- เพิ่มการจัดการความสามารถในการเป็นปัญหาเดียวกัน เพื่อป้องกันการประมวลผลซ้ำ
- เขียนการทดสอบแบบอัตโนมัติ สำหรับตัวจัดการเวบฮุกของคุณ
- ประมวลผลเวบฮุกแบบไม่ซิงโครนัส เพื่อประสิทธิภาพที่ดีขึ้น
- เพิ่มการบันทึกที่ครอบคลุม เพื่อการแก้ไขปัญหา
- ตั้งค่าการตรวจสอบสุ ขภาพเวบฮุก สำหรับโหมดการผลิต
- ทดสอบเหตุการณ์เวบฮุกทั้งหมด ที่แอปพลิเคชันของคุณจัดการ
พร้อมปรับใช้งาน ดูรายการตรวจสอบการทำงานเพื่อไปใช้งาน
ต้องการข้อมูลทดสอบ ดูเลขบัตรทดสอบและข้อมูล