استكشاف الأخطاء

Cloudflare Turnstile توقيت انتهاء صلاحية الرمز المميز وظروف السباق

رمز Turnstile الذي يعمل في الاختبار يفشل في الإنتاج. السبب: انتهاء صلاحية الرمز المميز. تتمتع رموز Turnstile بعمر محدود، وإذا استغرق سير العمل الخاص بك وقتًا طويلاً بين استلام الرمز المميز وإرساله، فسيرفضه الموقع. وإليك كيفية التعامل مع التوقيت بشكل صحيح.

عمر الرمز المميز

تنتهي صلاحية رموز Turnstile تقريبًا 300 ثانية (5 دقائق) بعد الإنشاء. يعد هذا أكثر سخاءً من مدة reCAPTCHA التي تبلغ حوالي 120 ثانية، ولكن لا تزال حالات السباق تنشأ في سير العمل المعقد.

نوع التحقق عمر الرمز
reCAPTCHA v2/v3 ~120 ثانية
Cloudflare Turnstile ~300 ثانية
hCaptcha ~120 ثانية

يبدأ المؤقت عندما يقوم Cloudflare بإنشاء الرمز المميز — وليس عندما يعيده CaptchaAI إليك، وليس عندما تستلمه في التعليمات البرمجية الخاصة بك.

حالة السباق

Time 0:00  — You submit a Turnstile task to CaptchaAI
Time 0:15  — CaptchaAI begins solving
Time 0:20  — Token is generated (timer starts here)
Time 0:25  — CaptchaAI returns token to you
Time 0:25+ — Your code processes the token
Time ???   — Your code submits the token to the site

الساعة تدق من الساعة 00:20 لديك حتى الساعة 5:20 تقريبًا لإرسال الرمز المميز. قد يبدو هذا سخيًا، ولكن فكر في ما يحدث في سير العمل الحقيقي:

Time 0:20  — Token generated
Time 0:25  — Received by your code
Time 0:30  — Fill form fields
Time 0:35  — Navigate to next page
Time 1:00  — Handle additional dialogs
Time 2:00  — Wait for page load
Time 4:00  — Network latency spike
Time 5:30  — Submit token → EXPIRED

سيناريوهات حالة السباق المشتركة

1. النماذج متعددة الخطوات

النماذج التي تتطلب عدة صفحات قبل التقديم النهائي:

Step 1: Fill personal info → Step 2: Fill address → 
Step 3: Solve CAPTCHA → Step 4: Review → Step 5: Submit

إذا كان اختبار CAPTCHA في الخطوة 3 ولكن تم الإرسال في الخطوة 5، فقد يتجاوز التأخير بين الحل والإرسال 5 دقائق.

2. قوائم انتظار المعالجة المجمعة

حل الرموز المميزة مسبقًا واستخدامها لاحقًا:

# DON'T: Solve all tokens first, then use them
tokens = []
for url in urls:
    tokens.append(solve_turnstile(url))  # Tokens age while waiting

for url, token in zip(urls, tokens):
    submit_form(url, token)  # Early tokens may be expired

3. أعد محاولة الحلقات باستخدام الرموز القديمة

إعادة استخدام الرمز المميز بعد فشل الإرسال:

token = solve_turnstile(site_key, page_url)

for attempt in range(3):
    result = submit_form(page_url, token)
    if result.ok:
        break
    # BUG: Retrying with the same token — it may be expired OR already consumed

منع انتهاء الصلاحية

الإستراتيجية 1: حل المشكلة في الوقت المناسب

اطلب الرمز المميز فقط عندما تكون مستعدًا للإرسال:

import requests
import time

def solve_turnstile(site_key, page_url):
    resp = requests.post("https://ocr.captchaai.com/in.php", data={
        "key": "YOUR_API_KEY",
        "method": "turnstile",
        "sitekey": site_key,
        "pageurl": page_url,
        "json": 1
    })
    task_id = resp.json()["request"]

    for _ in range(60):
        time.sleep(3)
        result = requests.get("https://ocr.captchaai.com/res.php", params={
            "key": "YOUR_API_KEY",
            "action": "get",
            "id": task_id,
            "json": 1
        })
        data = result.json()
        if data["status"] == 1:
            return data["request"]
    raise TimeoutError("Solve timed out")

# Complete all form steps FIRST
fill_personal_info()
fill_address()
navigate_to_review()

# THEN solve and submit immediately
token = solve_turnstile(site_key, page_url)
submit_form(token)  # Submit within seconds of receiving the token

الإستراتيجية 2: تتبع عمر الرمز المميز

import time

class TimedToken:
    def __init__(self, token, created_at=None):
        self.token = token
        self.created_at = created_at or time.time()
        self.max_age = 270  # 4.5 min — safety margin from 5 min limit

    @property
    def is_valid(self):
        return (time.time() - self.created_at) < self.max_age

    @property
    def remaining_seconds(self):
        return max(0, self.max_age - (time.time() - self.created_at))

# Usage
timed_token = TimedToken(solve_turnstile(site_key, page_url))

# Check before using
if timed_token.is_valid:
    submit_form(timed_token.token)
else:
    # Solve a fresh token
    timed_token = TimedToken(solve_turnstile(site_key, page_url))
    submit_form(timed_token.token)

الإستراتيجية 3: رمز جديد عند إعادة المحاولة (JavaScript)

async function submitWithFreshToken(siteKey, pageUrl, formData) {
  const maxRetries = 3;

  for (let attempt = 0; attempt < maxRetries; attempt++) {
    // Always solve a fresh token for each attempt
    const token = await solveTurnstile(siteKey, pageUrl);

    const response = await fetch(pageUrl, {
      method: 'POST',
      body: JSON.stringify({ ...formData, 'cf-turnstile-response': token }),
      headers: { 'Content-Type': 'application/json' }
    });

    if (response.ok) return await response.json();

    console.log(`Attempt ${attempt + 1} failed, solving fresh token...`);
  }

  throw new Error('All attempts failed');
}

كشف الرموز منتهية الصلاحية

لا يخبرك الموقع عادةً بأن "الرمز المميز منتهي الصلاحية" بشكل صريح. ابحث عن هذه الإشارات:

إشارة إشارة
HTTP 403 بعد إرسال الرمز المميز الرمز غير صالح أو منتهي الصلاحية
إعادة التوجيه مرة أخرى إلى صفحة النموذج فشل التحقق من الرمز المميز
رسالة الخطأ: "فشل التحقق" فشل عام - قد يكون انتهاء الصلاحية
تظهر صفحة التحدي مرة أخرى تم رفض الرمز المميز، وإعادة تحديات Cloudflare

تسجيل للتشخيص

import time
import logging

logging.basicConfig(level=logging.INFO)
logger = logging.getLogger("turnstile")

token_received_at = time.time()
token = solve_turnstile(site_key, page_url)
logger.info(f"Token received, length: {len(token)}")

# ... workflow steps ...

submit_time = time.time()
age = submit_time - token_received_at
logger.info(f"Submitting token, age: {age:.1f}s")

if age > 270:
    logger.warning(f"Token may be expired (age: {age:.1f}s > 270s safety limit)")

سلوك التحديث التلقائي للباب الدوار

في التدفقات المستندة إلى المستعرض، تقوم عناصر واجهة مستخدم Turnstile بتحديث الرموز المميزة تلقائيًا قبل انتهاء صلاحيتها. يتم تشغيل data-expired-callback عند انتهاء صلاحية الرمز المميز:

turnstile.render('#captcha', {
  sitekey: '0x4AAAA...',
  callback: (token) => {
    console.log('New token:', token);
  },
  'expired-callback': () => {
    console.log('Token expired — widget will auto-refresh');
  }
});

في التشغيل الآلي لواجهة برمجة التطبيقات (API) فقط (بدون متصفح)، لا تستفيد من التحديث التلقائي. يجب عليك إدارة نضارة الرمز المميز بنفسك.

استكشاف الأخطاء وإصلاحها

المشكلة السبب الإجراء
النتيجة لا تطابق الحالة الفعلية نوع CAPTCHA أو المعلمات لم تُطابَق مع الهدف الصحيح قارن الهدف وطريقة الحل والمعلمات المطلوبة مرة أخرى
الاختبار ينجح لكن بيئة الإنتاج تفشل الجلسة أو الرؤوس أو سياق الوكيل يختلف عن الاختبار أعد استخدام الشروط التي نجحت في الاختبار داخل سير العمل الفعلي كلما أمكن
المشكلة ما تزال غير واضحة السجلات لا تتضمن سياقًا كافيًا لتشخيص موثوق سجّل نوع الحل وزمن الاستجابة ورمز الخطأ والأثر اللاحق معًا

الخطوات التالية

أدلة ذات صلة

التعليقات غير مفعّلة لهذا المقال.