تكامل بوابات الدفع

تكامل Stripe مع React و Node.js: Payment Intents و Webhooks و 3D Secure

تكامل Stripe الإنتاجي مع Payment Intents و webhooks و 3D Secure. يغطي فواتير الاشتراكات ومعالجة الأخطاء وأنماط امتثال PCI.

Khalid Aboubakr
32 دقيقة قراءة
StripePayment GatewayReactNodejsPci ComplianceWebhooksSca3D SecurePayment Intents

جدول المحتويات

  1. لماذا هذا الدليل موجود
  2. نظرة عامة على البنية
  3. إعداد Stripe بشكل صحيح
  4. تنفيذ Payment Intents
  5. بناء نموذج الدفع في React
  6. تنفيذ Webhooks
  7. التعامل مع 3D Secure و SCA
  8. فواتير الاشتراكات
  9. معالجة الأخطاء التي تعمل فعلاً
  10. الأخطاء الشائعة في الإنتاج

لماذا هذا الدليل موجود

قمت بدمج Stripe في أكثر من عشرة أنظمة إنتاجية - منصات تجارة إلكترونية تعالج آلاف المعاملات اليومية، وتطبيقات SaaS بمستويات اشتراك معقدة، وأنظمة سوق بمدفوعات مقسمة. توثيق Stripe الرسمي جيد، لكنه لا يخبرك بما يحدث عندما تسوء الأمور في الساعة 2 صباحاً يوم الجمعة.

يغطي هذا الدليل ما كنت أتمنى معرفته قبل أول تكامل Stripe، وما تعلمته من تصحيح فشل المدفوعات في الإنتاج.

نظرة عامة على البنية

قبل كتابة الكود، افهم بنية تدفق الدفع:

┌─────────────────────────────────────────────────────────────────────┐
│                        تطبيقك                                        │
├─────────────────────────────────────────────────────────────────────┤
│  ┌──────────────┐     ┌──────────────┐     ┌──────────────┐        │
│  │  React UI   │────▶│  Your API    │────▶│   Database   │        │
│  │ (Stripe.js) │     │  (Node.js)   │     │              │        │
│  └──────────────┘     └──────────────┘     └──────────────┘        │
└─────────────────────────────────────────────────────────────────────┘
          │                    │
          ▼                    ▼
┌─────────────────────────────────────────────────────────────────────┐
│                         Stripe API                                   │
│  • لا يرى أبداً أرقام البطاقات الخام من خادمك                        │
│  • يتعامل مع تحديات 3D Secure                                       │
│  • يرسل webhooks للأحداث غير المتزامنة                               │
└─────────────────────────────────────────────────────────────────────┘

المبدأ الحاسم: خادمك لا يتعامل أبداً مع بيانات البطاقة الخام. Stripe.js يرمز تفاصيل البطاقة من جانب العميل.

إعداد Stripe بشكل صحيح

تكوين البيئة

// config/stripe.ts import Stripe from 'stripe'; if (!process.env.STRIPE_SECRET_KEY) { throw new Error('STRIPE_SECRET_KEY مطلوب'); } export const stripe = new Stripe(process.env.STRIPE_SECRET_KEY, { apiVersion: '2023-10-16', // دائماً ثبت إصدار API typescript: true, maxNetworkRetries: 2, timeout: 30000, });

لماذا تثبت إصدار API؟ Stripe تجري تغييرات جذرية. رأيت أنظمة إنتاج تتعطل لأنها ترقت تلقائياً إلى إصدار API جديد.

تنفيذ Payment Intents

Payment Intents هي واجهة Stripe الحديثة. لا تستخدم أبداً Charges API القديمة للتكاملات الجديدة.

جانب الخادم: إنشاء Payment Intents

export class PaymentService { async createPaymentIntent(params: CreatePaymentParams): Promise<{ clientSecret: string; paymentIntentId: string; }> { const { orderId, amount, currency } = params; // تحقق من وجود الطلب وإمكانية الدفع const order = await this.orderRepo.findById(orderId); if (!order) { throw new PaymentError('ORDER_NOT_FOUND', 'الطلب غير موجود'); } // تحقق من تطابق المبلغ مع إجمالي الطلب (منع التلاعب بالسعر) if (amount !== order.totalAmountCents) { throw new PaymentError('AMOUNT_MISMATCH', 'مبلغ الدفع لا يطابق الطلب'); } const paymentIntent = await stripe.paymentIntents.create({ amount, currency, metadata: { orderId }, automatic_payment_methods: { enabled: true }, }); return { clientSecret: paymentIntent.client_secret!, paymentIntentId: paymentIntent.id, }; } }

بناء نموذج الدفع في React

إعداد Stripe Elements

import { Elements } from '@stripe/react-stripe-js'; import { loadStripe } from '@stripe/stripe-js'; const stripePromise = loadStripe(process.env.NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY!); export function StripeProvider({ clientSecret, children }) { const options = { clientSecret, appearance: { theme: 'stripe', variables: { colorPrimary: '#0070f3', borderRadius: '8px', }, }, }; return ( <Elements stripe={stripePromise} options={options}> {children} </Elements> ); }

مكون نموذج الدفع

export function PaymentForm({ orderId, amount, currency, onSuccess, onError }) { const stripe = useStripe(); const elements = useElements(); const [isProcessing, setIsProcessing] = useState(false); const handleSubmit = async (event) => { event.preventDefault(); if (!stripe || !elements) return; setIsProcessing(true); const { error, paymentIntent } = await stripe.confirmPayment({ elements, confirmParams: { return_url: `${window.location.origin}/order/${orderId}/confirmation`, }, redirect: 'if_required', }); if (error) { onError(error.message); } else if (paymentIntent?.status === 'succeeded') { onSuccess(paymentIntent.id); } setIsProcessing(false); }; return ( <form onSubmit={handleSubmit}> <PaymentElement /> <button disabled={!stripe || isProcessing}> {isProcessing ? 'جارٍ المعالجة...' : `ادفع ${formatAmount(amount, currency)}`} </button> </form> ); }

تنفيذ Webhooks

هذا هو المكان الذي تفشل فيه معظم تكاملات Stripe. Webhooks هي الطريقة التي يخبرك بها Stripe عن الأحداث غير المتزامنة.

أمان Webhook

// حاسم: استخدم الجسم الخام للتحقق من التوقيع export function stripeWebhookMiddleware(req, res, next) { const signature = req.headers['stripe-signature']; try { const event = stripe.webhooks.constructEvent( req.body, // يجب أن يكون buffer خام، وليس JSON محلل signature, STRIPE_WEBHOOK_SECRET ); req.stripeEvent = event; next(); } catch (err) { return res.status(400).json({ error: 'توقيع غير صالح' }); } }

معالج Webhook مستقر

export class WebhookService { async handleEvent(event: Stripe.Event): Promise<void> { // فحص الاستقرار - هل عالجنا هذا الحدث؟ const existingEvent = await this.webhookRepo.findByEventId(event.id); if (existingEvent) { console.log(`الحدث ${event.id} معالج بالفعل، تخطي`); return; } // سجل الحدث قبل المعالجة await this.webhookRepo.create({ eventId: event.id, eventType: event.type, status: 'processing', }); try { await this.processEvent(event); await this.webhookRepo.markCompleted(event.id); } catch (error) { await this.webhookRepo.markFailed(event.id, error); throw error; } } private async handlePaymentSucceeded(paymentIntent: Stripe.PaymentIntent) { const orderId = paymentIntent.metadata.orderId; await this.paymentRepo.updateByPaymentIntentId(paymentIntent.id, { status: 'succeeded', paidAt: new Date(), }); await this.orderService.fulfillOrder(orderId); await this.notificationService.sendOrderConfirmation(orderId); } }

الأخطاء الشائعة في الإنتاج

1. عدم استخدام مفاتيح الاستقرار

// ❌ سيء: ينشئ رسوم مكررة عند إعادة المحاولة const paymentIntent = await stripe.paymentIntents.create({ amount: 1000, currency: 'usd', }); // ✅ جيد: آمن لإعادة المحاولة const paymentIntent = await stripe.paymentIntents.create( { amount: 1000, currency: 'usd' }, { idempotencyKey: `order_${orderId}_payment` } );

2. الوثوق بالمبلغ من جانب العميل

// ❌ سيء: المبلغ يأتي من العميل app.post('/create-payment', (req, res) => { const { amount } = req.body; // لا تثق بهذا أبداً }); // ✅ جيد: المبلغ من الطلب في الخادم app.post('/create-payment', (req, res) => { const order = await Order.findById(req.body.orderId); stripe.paymentIntents.create({ amount: order.totalCents }); });

3. عدم التعامل مع فشل Webhook

// ❌ سيء: نقطة فشل واحدة router.post('/webhook', (req, res) => { await processEvent(event); // إذا فشل هذا، الدفع ضائع res.json({ received: true }); }); // ✅ جيد: طابور مستمر للموثوقية router.post('/webhook', (req, res) => { await webhookQueue.add('process-stripe-event', event); res.json({ received: true }); // إقرار فوري });

الخلاصة

تكامل Stripe الإنتاجي يتطلب:

  1. لا تتعامل أبداً مع بيانات البطاقة الخام - استخدم Stripe.js و Payment Elements
  2. Webhooks مستقرة - مصدر الحقيقة الأساسي لحالة الدفع
  3. معالجة أخطاء صحيحة - حول أخطاء Stripe لرسائل صديقة للمستخدم
  4. دعم SCA/3D Secure - مطلوب في مناطق كثيرة
  5. مفاتيح الاستقرار - منع الرسوم المكررة
  6. التحقق من المبلغ في الخادم - لا تثق بالعميل أبداً

مقالات ذات صلة

تكامل بوابات الدفعقراءة 30 دقيقة

دليل تكامل Adyen: تنفيذ Drop-in Component و API

تكامل Adyen للمؤسسات مع Drop-in component و API. يغطي تكوين الدفع ومعالجة webhooks ودعم العملات المتعددة.