บทความทั้งหมด
เหตุการณ์เว็บฮุคการสมัครสมาชิกและใบอนุญาตไหลผ่านอุโมงค์ HTTPS ไปยังตัวจัดการการพัฒนาท้องถิ่นที่ได้รับการตรวจสอบ
Lemon Squeezywebhookssubscriptionslocal testing

ทดสอบเว็บฮุก Lemon Squeezy บน localhost

ในการทดสอบเว็บฮุคของ Lemon Squeezy บน localhost ให้เริ่มแอปของคุณ เปิดเผยเส้นทางเว็บฮุคของมันด้วยอุโมงค์ HTTPS สาธารณะ สร้างเว็บฮุคโหมดทดสอบใน การตั้งค่า → เว็บฮุค และตรวจสอบร่างคำขอดิบกับ X-Signature ส่วนหัว. ใช้การชำระเงินทดสอบสำหรับข้อมูลคำสั่งซื้อจริง และควบคุมการจำลองการสมัครสมาชิกของ Lemon Squeezy สำหรับเหตุการณ์วงจรชีวิตที่ยากต่อการรอ

ลักษณะของการตั้งค่าในพื้นที่ที่ถูกต้อง

Lemon Squeezy ส่ง HTTP POST จากโครงสร้างพื้นฐานของมัน ดังนั้นจึงไม่สามารถเข้าถึง localhost บนคอมพิวเตอร์ของคุณ ทางอุโมงค์จะสิ้นสุด TLS สาธารณะและส่งต่อวิธีการ เนื้อหา และส่วนหัวที่ไม่เปลี่ยนแปลงไปยังเส้นทางท้องถิ่น เช่น http://localhost:3000/api/webhooks/lemonsqueezy.

การทดสอบครบถ้วนมีสี่ส่วน: โหมดทดสอบ Lemon Squeezy, URL การเรียกกลับสาธารณะ, รหัสลับสำหรับการลงชื่อเดียวกันทั้งในแดชบอร์ดและสภาพแวดล้อมท้องถิ่น, และตัวจัดการที่ตรวจสอบก่อนที่จะเปลี่ยนสถานะการสมัครหรือใบอนุญาต สิ่งนี้มีประโยชน์มากกว่าการโพสต์ JSON ที่คัดลอกมา curlเพราะการจัดส่งจริงจะทดสอบทั้งการกำหนดเส้นทางและลายเซ็นที่สร้างโดยผู้ให้บริการ

สร้างเว็บฮุคและส่งเหตุการณ์ทดสอบ

  1. เรียกใช้แอปของคุณบนพอร์ต 3000 และตรวจสอบว่าเส้นทางยอมรับ POST.
  2. เริ่มอุโมงค์ด้วย npx portpreview 3000.
  3. สลับแดชบอร์ด Lemon Squeezy ไปยังโหมดทดสอบ
  4. เปิดการตั้งค่า → เว็บฮุคและเพิ่ม https://your-subdomain.portpreview.dev/api/webhooks/lemonsqueezy.
  5. สร้างความลับการลงชื่อแบบสุ่มที่แข็งแรง เก็บไว้เป็น LEMONSQUEEZY_WEBHOOK_SECRETและเลือกเฉพาะเหตุการณ์ที่แอปพลิเคชันของคุณใช้งาน
  6. สร้างการซื้อทดสอบหรือใช้การดำเนินการจำลองการสมัครสมาชิกโหมดทดสอบที่มีอยู่ จากนั้นตรวจสอบบันทึกการส่งและการตอบสนองภายในเครื่องของคุณ

ทางการ เอกสารเว็บฮุกของ Lemon Squeezy ช่วยให้คุณตรวจสอบ payloads ล่าสุดและส่ง webhook ที่บันทึกไว้ใหม่จากหน้าการตั้งค่า การส่งซ้ำมีประโยชน์สำหรับการทดสอบ regression แต่แอปพลิเคชันของคุณต้องถือว่าเป็นรายการซ้ำแทนที่จะเป็นเหตุการณ์ทางธุรกิจครั้งที่สอง

ตรวจสอบ X-Signature ก่อนวิเคราะห์ JSON

Lemon Squeezy คำนวณ digest แบบ HMAC-SHA256 เหนือ payload ของคำขอโดยใช้ความลับการเซ็นและส่ง digest ในรูปแบบเลขฐานสิบหก X-Signature. คำนวณแฮชจากไบต์ของเนื้อหาดิบที่แน่นอนและเปรียบเทียบบัฟเฟอร์ที่มีความยาวเท่ากันด้วยฟังก์ชันที่ใช้เวลาคงที่ หลัก เอกสารการขอลงนาม รวมตัวอย่างสำหรับ Node, PHP, Python และ Ruby

// app/api/webhooks/lemonsqueezy/route.ts
import crypto from 'node:crypto';
import { NextRequest, NextResponse } from 'next/server';

export async function POST(request: NextRequest) {
  const secret = process.env.LEMONSQUEEZY_WEBHOOK_SECRET;
  if (!secret) return new NextResponse('server misconfigured', { status: 500 });

  const rawBody = await request.text();
  const suppliedHex = request.headers.get('x-signature') ?? '';

  if (!/^[0-9a-f]{64}$/i.test(suppliedHex)) {
    return new NextResponse('invalid signature', { status: 401 });
  }

  const expected = crypto
    .createHmac('sha256', secret)
    .update(rawBody)
    .digest();
  const supplied = Buffer.from(suppliedHex, 'hex');

  if (supplied.length !== expected.length ||
      !crypto.timingSafeEqual(supplied, expected)) {
    return new NextResponse('invalid signature', { status: 401 });
  }

  const event = JSON.parse(rawBody);
  await acceptEvent(event);
  return NextResponse.json({ received: true });
}

อย่าโทร request.json() อันดับแรก การทำการเรียงลำดับใหม่ของวัตถุที่ได้อาจเปลี่ยนไบต์ที่ดูไม่สำคัญและทำให้ HMAC เสีย การตรวจสอบความยาวก็เป็นสิ่งสำคัญเช่นกันเพราะ Node's timingSafeEqual ทำงานผิดพลาดเมื่อความยาวบัฟเฟอร์แตกต่างกัน อย่างเป็นทางการของ Lemon Squeezy บทเรียนเว็บฮุก Next.js ตามลำดับร่างดิบเดียวกัน

เข้าใจข้อมูลเพย์โหลดก่อนอัปเดตฐานข้อมูลของคุณ

ร่างกายคือวัตถุทรัพยากร JSON:API meta.event_name ระบุเหตุการณ์ meta.custom_data ส่งข้อมูลที่ผ่านการชำระเงินมา และ data ประกอบด้วยคำสั่งซื้อ การสมัครสมาชิก หรือทรัพยากรคีย์ใบอนุญาต Lemon Squeezy ยังส่ง X-Event-Name; พิจารณาร่างที่ลงนามแล้วเป็นข้อมูลหลักและใช้ส่วนหัวสำหรับวินิจฉัยการกำหนดเส้นทาง

คำสั่งซื้อและตัวตนของลูกค้า

สำหรับ order_created, ทำการแมปการซื้อไปยังผู้ใช้ภายในโดยใช้ตัวระบุที่สร้างโดยเซิร์ฟเวอร์ในข้อมูลกำหนดเองของการชำระเงิน ไม่ควรเชื่อถือรหัสผู้ใช้ที่ผู้ใช้ให้มาโดยไม่ตรวจสอบความเป็นเจ้าของ เก็บ ID ของทรัพยากรและ ID ของตัวแปรของ Lemon Squeezy ไว้เพื่อให้สามารถปรับยอดเหตุการณ์การสมัครสมาชิกหรือการคืนเงินในภายหลังได้

การสมัครสมาชิกเป็นเครื่องจักรสถานะ

จัดการ subscription_created, subscription_updated, subscription_cancelled, subscription_resumed, และ subscription_expired เป็นการเปลี่ยนผ่านที่แตกต่างกัน การยกเลิกอาจหมายความว่าการเข้าถึงยังคงใช้ได้จนกว่าจะสิ้นสุดรอบการเรียกเก็บเงิน; การหมดอายุเป็นสัญญาณที่ชัดเจนกว่าว่าสมาชิกภาพได้สิ้นสุดลง แล้วจัดการวันที่และสถานะของโมเดลแทนการสลับค่า boolean เพียงค่าเดียว

ความล้มเหลวในการชำระเงินและการกู้คืน

ทดสอบการล้มเหลวและการกู้คืนกระบวนการต่ออายุในกรณีที่โหมดทดสอบรองรับ การชำระเงินล้มเหลวไม่จำเป็นต้องยกเลิกการเข้าถึงทันที ให้ใช้ระยะเวลาปลอดชำระหนี้ตามที่นโยบายผลิตภัณฑ์ของคุณกำหนด และปล่อยให้การชำระเงินหรือเหตุการณ์การสมัครสมาชิกในภายหลังทำให้บัญชีสอดคล้องกับสถานะผู้ให้บริการล่าสุด

การลองใหม่ต้องใช้การประมวลผลแบบไม่เปลี่ยนผลลัพธ์

ตามที่ Lemon Squeezy กล่าว การอ้างอิงคำขอเว็บฮุค, a 200 เครื่องหมายการตอบสนองจับได้ว่าเป็นความสำเร็จ สถานะอื่น ๆ จะถูกลองใหม่อีกสูงสุดสามครั้งโดยมีการหน่วงเวลาตามกำลังที่แสดงเป็นประมาณ 5, 25, และ 125 วินาที แดชบอร์ดส่งซ้ำสร้างเหตุผลอีกครั้งว่ากิจกรรมทางตรรกะเดียวกันสามารถมาถึงมากกว่าหนึ่งครั้ง

สร้างคีย์ idempotency จากฟิลด์ payload ที่ลงนามอย่างมั่นคง วิธีปฏิบัติที่เหมาะสมคือต้องมีแถวฐานข้อมูลที่ไม่ซ้ำกันสำหรับ ID ของ resource ของ webhook, ชื่อเหตุการณ์, และเวลาประทับเหตุการณ์ หรือแฮชของเนื้อหาที่ลงนามดิบเมื่อไม่มี ID ของเหตุการณ์เฉพาะ แทรกรายการนั้นและอัปเดตสถานะของแอปพลิเคชันในธุรกรรมเดียว คืนค่า 200 สำหรับสำเนาที่เสร็จสิ้นแล้วก่อนหน้านี้

BEGIN;
INSERT INTO webhook_receipts (fingerprint, received_at)
VALUES ($1, now())
ON CONFLICT DO NOTHING;
-- Continue only if one row was inserted.
UPDATE subscriptions SET provider_status = $2 WHERE provider_id = $3;
COMMIT;

อย่านำการส่งอีเมลหรือการเรียก API ของบุคคลที่สามที่ช้าไปเป็นส่วนหนึ่งของเส้นทางการยืนยัน ให้เก็บงานในธุรกรรมเดียวกัน ตอบกลับ และให้พนักงานจัดการผลข้างเคียง ส่วนที่กว้างขึ้น คู่มือการลองส่งเว็บฮุคใหม่และความไม่ซ้ำกันของคำสั่ง ครอบคลุมรูปแบบนี้

การแก้ไขปัญหาการทดสอบ webhook ของ Lemon Squeezy บน localhost

ไม่มีคำขอใดเข้าถึงแอป

ตรวจสอบว่าท่อยังทำงานอยู่หรือไม่, การเรียกกลับมีส่วนต่อท้ายเส้นทาง, และเฟรมเวิร์กของคุณมีตัวจัดการ POST ที่เส้นทางนั้นพอดี ลองเรียกใช้งานเอ็นด์พอยต์สาธารณะด้วยตัวเอง ท่อ 502 ชี้ไปที่พอร์ตภายในเครื่อง; เฟรมเวิร์ก 404 ชี้ไปที่การวางเส้นทาง

ลายเซ็นทุกอันไม่ถูกต้อง

ยืนยันว่าโหมดทดสอบและโหมดใช้งานจริงไม่ได้ใช้บันทึก webhook หรือความลับที่ต่างกัน อ่านเนื้อหาเพียงครั้งเดียวในรูปแบบข้อความหรือไบต์ อย่าตัดเนื้อหาหรือความลับ และตรวจสอบให้แน่ใจว่า middleware JSON แบบทั่วโลกไม่ทำงานก่อน ตรวจสอบว่า X-Signature มาถึงแล้ว แต่ไม่เคยพิมพ์ความลับในการลงชื่อ

การจัดส่งพยายามส่งซ้ำอยู่ตลอด

เลมอน สกีซซี่ คาดหวัง 200, ไม่ใช่การเปลี่ยนเส้นทางไปยังหน้าล็อกอิน ยกเว้นเส้นทาง webhook จาก CSRF และ middleware ของเซสชันผู้ใช้ในขณะที่ยังคงการตรวจสอบลายเซ็น ตรวจจับข้อผิดพลาดของฐานข้อมูล ทำให้การทำงานสั้น และตรวจสอบให้แน่ใจว่ามีการส่งการตอบกลับความสำเร็จจริง ๆ ในทุกสาขาของเหตุการณ์ที่จัดการแล้ว

การจำลองการสมัครใช้งานไม่สามารถใช้งานได้

การควบคุมการจำลองต้องการข้อมูลการสมัครใช้งานโหมดทดสอบที่เหมาะสม การจำลองการชำระเงินบางรายการจำเป็นต้องมีประวัติการต่ออายุ สร้างการสมัครใช้งานทดสอบหรือการซื้อทดสอบที่จำเป็นก่อน จากนั้นใช้เมนูการดำเนินการสมัครสมาชิกตามที่อธิบายใน Lemon Squeezy คู่มือสำหรับนักพัฒนาเว็บฮุก.

รายการตรวจสอบความปลอดภัยและการเริ่มใช้งานจริง

  • สร้างรหัสลับสำหรับการเซ็นแบบสุ่ม เก็บไว้ในการตั้งค่าสภาพแวดล้อม และหมุนมันหากถูกเปิดเผย
  • ตรวจสอบ HMAC บนตัวเนื้อหาดิบก่อนการแยกวิเคราะห์ JSON การเขียนฐานข้อมูล การสร้างใบอนุญาต หรือการเปลี่ยนแปลงการเข้าถึง
  • ใช้การเปรียบเทียบที่ปลอดภัยต่อเวลาและปฏิเสธลายเซ็นที่หายไปหรือมีรูปแบบไม่ถูกต้อง
  • เก็บความลับและบันทึกของโหมดทดสอบและเว็บฮุคสดแยกจากกัน
  • อนุญาตเฉพาะ POST บังคับใช้ขีดจำกัดขนาดเนื้อหาที่เหมาะสม จำกัดความถี่ของคำขอที่ไม่ถูกต้อง และลบข้อมูลลูกค้าออกจากบันทึก
  • ทดสอบการทำซ้ำ เหตุการณ์วงจรชีวิตที่ไม่เรียงลำดับ การหยุดทำงานของฐานข้อมูล และการกู้คืนเมื่อหมดเวลา ก่อนที่จะเปลี่ยนช่องท่อเป็น URL การผลิตของคุณ

การชำระเงินแบบเส้นทางความสุขที่ผ่านไปได้พิสูจน์เพียงว่าเหตุการณ์หนึ่งเกิดขึ้น การรวมระบบที่พร้อมใช้งานในสภาพการผลิตพิสูจน์การปฏิเสธลายเซ็นต์ ความปลอดภัยต่อการซ้ำ การรวมวงจรชีวิต และการกู้คืนจากการตอบสนองที่ไม่ใช่ 200 สำหรับกับดักการเข้ารหัสลับพื้นฐาน ดูที่ คู่มือการตรวจสอบลายเซ็น.

คำถามที่พบบ่อย

ฉันจะทดสอบเว็บฮุคของ Lemon Squeezy บน localhost ได้อย่างไร?
เปิดเผยเส้นทางเว็บฮุกท้องถิ่นของคุณด้วยอุโมงค์ HTTPS สร้างเว็บฮุกในขณะที่แดชบอร์ดอยู่ในโหมดทดสอบ ใช้ความลับการลงชื่อเดิมในเครื่องท้องถิ่น และกระตุ้นการชำระเงินทดสอบหรือการจำลองการสมัครสมาชิกที่รองรับ
การตรวจสอบลายเซ็น webhook ของ Lemon Squeezy ทำอย่างไร?
คำนวณค่า HMAC-SHA256 digest บนเนื้อหาคำขอแบบดิบที่ตรงตามต้นฉบับด้วยรหัสลับสำหรับการลงชื่อของคุณ ถอดรหัสค่าที่เป็นเลขฐานสิบหกของ X-Signature และเปรียบเทียบบัฟเฟอร์ที่มีความยาวเท่ากันด้วยฟังก์ชันที่ปลอดภัยต่อเวลา
Lemon Squeezy จะลองใหม่กับเว็บฮุคที่ล้มเหลวหรือไม่?
ใช่ เอกสารของมันระบุว่าการตอบสนองที่ไม่ใช่ 200 จะถูกลองใหม่ได้สูงสุดสามครั้งเพิ่มเติมโดยมีการหน่วงเวลาลดหลั่นแบบทวีคูณ ประมาณหลังจาก 5, 25 และ 125 วินาที
ฉันสามารถจำลองการต่ออายุการสมัคร Lemon Squeezy ในโหมดทดสอบได้หรือไม่?
โหมดทดสอบให้การจำลองการดำเนินการสำหรับเหตุการณ์การสมัครสมาชิกที่รองรับ การจำลองบางอย่างที่เกี่ยวข้องกับการชำระเงินจำเป็นต้องมีการสมัครสมาชิกทดสอบและข้อมูลการต่ออายุที่มีอยู่ ดังนั้นสร้างสถานะทดสอบที่จำเป็นก่อน