خطأ timeout-or-duplicate هو فشل reCAPTCHA الأكثر شيوعًا في سير عمل التشغيل الآلي. هذا يعني أن الرمز المميز الخاص بك قد انتهت صلاحيته قبل الإرسال أو تم استخدامه مرتين. نظرًا لأن رموز reCAPTCHA تدوم لمدة 120 ثانية فقط وتستغرق أدوات حل واجهة برمجة التطبيقات (API) ما بين 15 إلى 45 ثانية لإنشاءها، فإن إدارة التوقيت أمر بالغ الأهمية. يغطي هذا الدليل آليات انتهاء الصلاحية الدقيقة وظروف السباق الشائعة واستراتيجيات التوقيت العملية.
قاعدة الـ 120 ثانية
تنتهي صلاحية كل رمز reCAPTCHA بعد 120 ثانية بالضبط من إنشائه. وهذا ينطبق على جميع الإصدارات:
Token generated (solve complete)
├─── 0s: Token is valid ✓
├─── 60s: Token is valid ✓
├─── 110s: Token is valid ✓ (but cutting it close)
├─── 119s: Token is valid ✓ (dangerous territory)
└─── 120s: Token EXPIRED ✗ (timeout-or-duplicate)
حيث يبدأ الموقت
| السيناريو | يبدأ المؤقت عندما... |
|---|---|
| خانة الاختيار reCAPTCHA v2 | يحدد المستخدم مربع الاختيار (تم حل التحدي) |
| شبكة الصور reCAPTCHA v2 | يكمل المستخدم جولة اختيار الصورة النهائية |
| reCAPTCHA v2 غير مرئية | يتم تشغيل رد الاتصال execute() باستخدام الرمز المميز |
| reCAPTCHA v3 | execute() يتم حل الوعد بالرمز المميز |
| محلل واجهة برمجة التطبيقات (CaptchaAI) | يقوم Solver بإنشاء الرمز المميز (وليس عند استلامه) |
فجوة توقيت الحل
عند استخدام محلل واجهة برمجة التطبيقات، يكون هناك تأخير بين وقت إنشاء المحلل للرمز المميز ووقت استلام الرمز الخاص بك له:
Solver generates token (timer starts)
↓ ~1-5 seconds (network + polling interval)
Your code receives token via res.php poll
↓ You now have ~115-119 seconds remaining
Your code processes and submits token
↓ ~1-10 seconds (depends on your workflow)
Target website validates token with Google
↓ ~1-2 seconds (Google API response time)
Total remaining after validation: ~105-117 seconds (comfortable)
من الناحية العملية، توفر النافذة التي تبلغ 120 ثانية وقتًا كافيًا لإرسال الرمز الخاص بك فورًا بعد استلام الرمز المميز. تحدث المشاكل عندما:
- يحتوي الرمز الخاص بك على خطوات معالجة إضافية بين استلام الرمز المميز وإرساله
- يجب ملء نماذج متعددة قبل الإرسال
- موقع الويب المستهدف لديه وقت استجابة بطيء
- يمكنك وضع الرموز المميزة في قائمة الانتظار وإرسالها لاحقًا
ظروف السباق المشتركة
حالة السباق 1: حل متوازي + إرسال متسلسل
# WRONG: Solving multiple CAPTCHAs in parallel, then submitting sequentially
tokens = []
for url in urls:
task_id = solve_captcha(url) # All submitted at t=0
tokens.append(task_id)
# All tokens arrive around t=30
solved_tokens = [poll_result(tid) for tid in tokens]
# Sequential submission: first token at t=32, last at t=120+
for i, (url, token) in enumerate(zip(urls, solved_tokens)):
submit_form(url, token) # Later tokens may be expired!
time.sleep(10) # Each wait adds pressure
الإصلاح: قم بحل كل اختبار CAPTCHA وإرساله قبل بدء الاختبار التالي:
# CORRECT: Solve and submit one at a time
for url in urls:
token = solve_and_wait(url) # Token received at t=30
submit_form(url, token) # Submitted at t=31 (89 seconds remaining)
حالة السباق 2: الجلب المسبق للرمز المميز
# WRONG: Pre-fetching tokens before knowing when they'll be used
token = solve_captcha() # Token received at t=0
# ... user fills out form (30-120+ seconds) ...
# ... validation checks ...
# ... other processing ...
submit_form(token) # Token may be expired!
الإصلاح: حل اختبار CAPTCHA كخطوة أخيرة قبل الإرسال:
# CORRECT: Late-bind the CAPTCHA solve
prepare_form_data() # Do everything that doesn't need the token
validate_inputs() # Run validation before spending a token
# Now solve and submit immediately
token = solve_captcha() # Token received at t=0
submit_form(token) # Submitted at t=1 (119 seconds remaining)
حالة السباق 3: تقديم نموذج متعدد الخطوات
# PROBLEMATIC: Multi-step form where CAPTCHA is on step 1 but submit is step 3
token = solve_captcha() # t=0: Token received
fill_step_1(token) # t=5: Step 1 submitted
response = fill_step_2() # t=15: Step 2 completed
# ... step 2 has additional verification ...
wait_for_verification() # t=60: Verification complete
fill_step_3_and_submit() # t=65: Final submission (55 seconds remaining - OK)
# BUT if step 2 takes longer than expected...
الإصلاح: قياس عمر الرمز المميز وإعادة الحل إذا لزم الأمر:
token_received_at = time.time()
token = solve_captcha()
token_received_at = time.time()
# ... multi-step process ...
# Before final submission, check token age
token_age = time.time() - token_received_at
if token_age > 100: # 20-second safety margin
print(f"Token is {token_age:.0f}s old — requesting fresh token")
token = solve_captcha()
token_received_at = time.time()
submit_final(token)
مدير توقيت الرمز المميز
فئة جاهزة للإنتاج لإدارة عمر الرمز المميز:
import time
import requests
class TokenTimingManager:
"""Manage reCAPTCHA token timing to prevent expiration errors."""
API_KEY = "YOUR_API_KEY"
TOKEN_LIFETIME = 120
SAFETY_MARGIN = 15 # seconds before expiry to consider "stale"
def __init__(self, site_key, page_url, version="v2"):
self.site_key = site_key
self.page_url = page_url
self.version = version
self.current_token = None
self.token_timestamp = None
def _solve(self):
"""Request and poll for a new token."""
params = {
"key": self.API_KEY,
"method": "userrecaptcha",
"googlekey": self.site_key,
"pageurl": self.page_url,
"json": 1,
}
if self.version == "v3":
params.update({"version": "v3", "action": "submit"})
submit = requests.post("https://ocr.captchaai.com/in.php", data=params).json()
task_id = submit["request"]
for _ in range(60):
time.sleep(5)
result = requests.get("https://ocr.captchaai.com/res.php", params={
"key": self.API_KEY,
"action": "get",
"id": task_id,
"json": 1,
}).json()
if result.get("status") == 1:
self.current_token = result["request"]
self.token_timestamp = time.time()
return self.current_token
raise TimeoutError("Token solve timeout")
@property
def token_age(self):
"""Seconds since current token was received."""
if self.token_timestamp is None:
return float("inf")
return time.time() - self.token_timestamp
@property
def token_remaining(self):
"""Seconds remaining before token expires."""
return max(0, self.TOKEN_LIFETIME - self.token_age)
@property
def is_fresh(self):
"""Whether the token is fresh enough to use."""
return self.token_remaining > self.SAFETY_MARGIN
def get_token(self):
"""Get a valid token, solving if current is stale or missing."""
if self.current_token and self.is_fresh:
return self.current_token
return self._solve()
def use_token(self):
"""Get and consume a token (cannot be reused)."""
token = self.get_token()
# Mark as consumed
self.current_token = None
self.token_timestamp = None
return token
# Usage
manager = TokenTimingManager(
site_key="6LcR_RsTAAAAAN_r0GEkGBfq3L7KmU5JbPHJtwNp",
page_url="https://example.com/login",
)
# Get a fresh token right before submission
token = manager.use_token()
print(f"Token remaining: {manager.TOKEN_LIFETIME}s (fresh solve)")
# Submit form with token...
معالجة خطأ المهلة أو التكرار
عندما تتلقى timeout-or-duplicate، قم بتشخيص السبب:
def handle_recaptcha_error(error_codes, token_age_seconds):
"""Diagnose and handle reCAPTCHA validation errors."""
if "timeout-or-duplicate" in error_codes:
if token_age_seconds > 120:
return {
"cause": "Token expired (age: {:.0f}s > 120s)".format(token_age_seconds),
"fix": "Reduce time between receiving and submitting token",
"action": "re-solve",
}
elif token_age_seconds < 5:
return {
"cause": "Token likely reused (duplicate submission)",
"fix": "Ensure each form submission gets a unique token",
"action": "re-solve",
}
else:
return {
"cause": "Token may have been reused or server-side timing issue",
"fix": "Check for double-submit in form handler",
"action": "re-solve",
}
if "invalid-input-response" in error_codes:
return {
"cause": "Token is malformed or corrupted",
"fix": "Check token transmission (URL encoding, field name)",
"action": "re-solve",
}
return {"cause": "Unknown", "action": "investigate"}
توقيت أفضل الممارسات
| ممارسة | توصية |
|---|---|
| ** فجوة الحل للإرسال ** | احتفظ بأقل من 90 ثانية (هامش 30 ثانية) |
| فاصل الاستطلاع | 5 ثوانٍ بين عمليات فحص res.php |
| الحل المسبق | قم بالحل المسبق فقط إذا كنت تعلم أن الإرسال سيتم خلال 60 ثانية |
| إعادة المحاولة عند انتهاء الصلاحية | اطلب دائمًا رمزًا مميزًا جديدًا على timeout-or-duplicate |
| ** قائمة الانتظار الرمزية ** | لا تقم أبدًا بوضع الرموز المميزة في قائمة الانتظار، فكل منها تنتهي صلاحيته بشكل مستقل |
| العمليات الموازية | حل لكل مهمة، وليس حل كل شيء ثم الاستخدام |
| الرصد | تتبع عمر الرمز المميز في وقت التقديم |
الأسئلة المتداولة
هل يمكنني تمديد نافذة الرمز المميز لمدة 120 ثانية؟
لا. يتم فرض انتهاء الصلاحية من جانب الخادم بواسطة Google ولا يمكن تمديده بأي وسيلة. 120 ثانية هي حد صعب.
هل يؤدي تأخير الاقتراع إلى تقليل وقت الرمز المميز القابل للاستخدام؟
نعم قليلا. إذا قمت بالاستقصاء كل 5 ثوانٍ، فقد تتلقى الرمز المميز لمدة تصل إلى 5 ثوانٍ بعد إنشائه. عمليًا، هذا يعني أن لديك حوالي 115 ثانية بدلاً من 120. وهذا عادةً لا يمثل مشكلة.
هل يجب أن أقوم بحل الرموز المميزة مسبقًا حتى تكون جاهزة؟
فقط إذا كان بإمكانك ضمان إرسال الرمز المميز خلال 60-90 ثانية. يعد الحل المسبق مفيدًا لسير العمل الحساس لزمن الوصول (على سبيل المثال، الشراء التنافسي) حيث يكون وقت الحل الإضافي الذي يتراوح من 15 إلى 45 ثانية مهمًا. بالنسبة لمعظم عمليات سير العمل، يعد الحل عند الطلب أكثر أمانًا.
لماذا تستخدم Google نفس الخطأ للرموز المميزة منتهية الصلاحية والمكررة؟
تحجب Google التمييز عمدًا لمنع البرامج النصية للتشغيل الآلي من استخدام رمز الخطأ لاكتشاف الحالة التي حدثت. كلتا الحالتين لهما نفس العلاج: طلب رمز مميز جديد.
ملخص
تنتهي صلاحية رموز reCAPTCHA بعد 120 ثانية بالضبط، ولا يمكن استخدامها إلا مرة واحدة. يحدث خطأ الأتمتة الأكثر شيوعًا — timeout-or-duplicate — بسبب إرسال الرموز المميزة في وقت متأخر جدًا أو إعادة استخدامها. عند الاستخدامCaptchaAI، قم بحل الرموز المميزة قبل الإرسال مباشرةً، وتتبع عمر الرمز المميز، ولا تضع الرموز المميزة في قائمة الانتظار أو تعيد استخدامها أبدًا. استخدم نمط مدير التوقيت أعلاه للتعامل تلقائيًا مع انتهاء الصلاحية وإعادة الحل في سير عمل الإنتاج.
مقالات ذات صلة
- كيفية حل رد اتصال Recaptcha V2 باستخدام Api
- التعامل مع reCAPTCHA v2 وTurnstile في الموقع نفسه
- شرح دورة حياة رمز Recaptcha
أدلة ذات صلة
- البدء السريع مع CaptchaAI: حلّ أول كابتشا في 5 دقائق
- كيفية حلّ reCAPTCHA v2 عبر الـ API: دليل خطوة بخطوة