Khắc Phục Sự Cố

Hết hạn mã thông báo reCAPTCHA: Thời gian Windows và điều kiện cuộc đua

Lỗi timeout-or-duplicate là lỗi reCAPTCHA phổ biến nhất trong quy trình tự động hóa. Điều đó có nghĩa là mã thông báo của bạn đã hết hạn trước khi gửi hoặc đã được sử dụng hai lần. Với mã thông báo reCAPTCHA chỉ tồn tại trong 120 giây và trình giải mã API mất 15-45 giây để tạo chúng, việc quản lý thời gian là rất quan trọng. Hướng dẫn này đề cập đến cơ chế hết hạn chính xác, điều kiện chung của cuộc đua và chiến lược tính thời gian thực tế.


Quy tắc 120 giây

Mỗi mã thông báo reCAPTCHA sẽ hết hạn đúng 120 giây sau khi tạo. Điều này áp dụng cho tất cả các phiên bản:

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)

Nơi bộ đếm thời gian bắt đầu

Kịch bản Bộ hẹn giờ bắt đầu khi...
Hộp kiểm reCAPTCHA v2 Người dùng chọn hộp kiểm (thách thức đã được giải quyết)
Lưới hình ảnh reCAPTCHA v2 Người dùng hoàn thành vòng lựa chọn hình ảnh cuối cùng
reCAPTCHA v2 vô hình Lệnh gọi lại execute() kích hoạt bằng mã thông báo
reCAPTCHA v3 Lời hứa execute() được giải quyết bằng mã thông báo
Bộ giải API (CaptchaAI) Bộ giải tạo mã thông báo (KHÔNG phải khi bạn nhận được nó)

Khoảng cách thời gian của người giải quyết

Khi sử dụng bộ giải API, sẽ có độ trễ giữa thời điểm bộ giải tạo mã thông báo và thời điểm mã của bạn nhận được mã đó:

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)

Trong thực tế, khoảng thời gian 120 giây cung cấp nhiều thời gian khi mã của bạn gửi ngay sau khi nhận được mã thông báo. Các vấn đề xảy ra khi:

  • Mã của bạn có các bước xử lý bổ sung giữa việc nhận mã thông báo và gửi mã thông báo
  • Cần phải điền nhiều biểu mẫu trước khi gửi
  • Trang web mục tiêu có thời gian phản hồi chậm
  • Bạn xếp hàng mã thông báo và gửi chúng sau

Điều kiện chủng tộc chung

Điều kiện cuộc đua 1: Giải song song + gửi tuần tự

# 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

Khắc phục: Giải và gửi từng CAPTCHA trước khi bắt đầu lần tiếp theo:

# 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)

Điều kiện cuộc đua 2: Tìm nạp trước mã thông báo

# 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!

Khắc phục: Giải CAPTCHA là bước cuối cùng trước khi gửi:

# 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)

Điều kiện cuộc đua 3: Gửi biểu mẫu nhiều bước

# 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...

Khắc phục: Đo tuổi mã thông báo và giải quyết lại nếu cần:

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)

Trình quản lý thời gian mã thông báo

Lớp sẵn sàng sản xuất để quản lý vòng đời của mã thông báo:

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://staging.example.com/qa-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...

Xử lý lỗi hết thời gian chờ hoặc trùng lặp

Khi bạn nhận được timeout-or-duplicate, hãy chẩn đoán nguyên nhân:

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"}

Thực hành tốt nhất về thời gian

Thực hành Khuyến nghị
Khoảng cách giải quyết để gửi Giữ dưới 90 giây (lề 30 giây)
** Khoảng thời gian thăm dò ý kiến ** 5 giây giữa các lần kiểm tra res.php
Giải quyết trước Chỉ giải quyết trước nếu bạn biết việc gửi sẽ diễn ra trong vòng 60 giây
Thử lại khi hết hạn Luôn yêu cầu mã thông báo mới trên timeout-or-duplicate
Hàng đợi mã thông báo Không bao giờ xếp hàng mã thông báo - mỗi mã hết hạn một cách độc lập
Hoạt động song song Giải quyết theo nhiệm vụ, không phải giải quyết tất cả rồi sử dụng
Giám sát Theo dõi tuổi mã thông báo tại thời điểm gửi

Câu hỏi thường gặp

Tôi có thể mở rộng thời lượng mã thông báo 120 giây không?

Không. Google thực thi việc hết hạn ở phía máy chủ và không thể gia hạn bằng bất kỳ cách nào. 120 giây là một giới hạn cứng.

Việc trì hoãn bỏ phiếu có làm giảm thời gian sử dụng mã thông báo của tôi không?

Vâng, hơi. Nếu bạn thăm dò ý kiến ​​cứ sau 5 giây, bạn có thể nhận được mã thông báo tối đa 5 giây sau khi mã được tạo. Trong thực tế, điều này có nghĩa là bạn có ~115 giây thay vì 120. Điều này thường không thành vấn đề.

Tôi có nên giải quyết trước các mã thông báo để chuẩn bị sẵn sàng không?

Chỉ khi bạn có thể đảm bảo mã thông báo sẽ được gửi trong vòng 60-90 giây. Việc giải quyết trước rất hữu ích cho các quy trình làm việc nhạy cảm với độ trễ (ví dụ: mua hàng cạnh tranh), trong đó thời gian giải quyết thêm 15-45 giây rất quan trọng. Đối với hầu hết các quy trình công việc, giải quyết theo yêu cầu sẽ an toàn hơn.

Tại sao Google sử dụng cùng một lỗi cho các mã thông báo đã hết hạn và trùng lặp?

Google cố tình che giấu sự khác biệt để ngăn chặn các tập lệnh tự động hóa sử dụng mã lỗi để phát hiện trường hợp nào đã xảy ra. Cả hai trường hợp đều có cùng một biện pháp khắc phục: yêu cầu mã thông báo mới.


Tóm tắt

Mã thông báo reCAPTCHA hết hạn sau đúng 120 giây và chỉ có thể được sử dụng một lần. Lỗi tự động hóa phổ biến nhất – timeout-or-duplicate – là do gửi mã thông báo quá muộn hoặc sử dụng lại chúng. Khi sử dụngCaptchaAI, giải quyết mã thông báo ngay trước khi gửi, theo dõi tuổi của mã thông báo và không bao giờ xếp hàng hoặc sử dụng lại mã thông báo. Sử dụng mẫu trình quản lý thời gian ở trên để tự động xử lý hết hạn và giải quyết lại trong quy trình sản xuất.

bài viết liên quan

Os comentários estão desativados para este artigo.