Mã thông báo Turnstile hoạt động trong quá trình thử nghiệm không thành công trong quá trình sản xuất. Nguyên nhân: hết hạn token. Mã thông báo quay vòng có thời gian tồn tại giới hạn và nếu quy trình làm việc của bạn mất quá nhiều thời gian từ lúc nhận mã thông báo đến khi gửi mã thông báo thì trang web sẽ từ chối mã thông báo đó. Đây là cách xử lý thời gian một cách chính xác.
Tuổi thọ của mã thông báo
Mã thông báo quay vòng hết hạn khoảng 300 giây (5 phút) sau khi tạo. Con số này cao hơn ~120 giây của reCAPTCHA, nhưng điều kiện chạy đua vẫn phát sinh trong quy trình làm việc phức tạp.
| loại CAPTCHA | Tuổi thọ của mã thông báo |
|---|---|
| reCAPTCHA v2/v3 | ~120 giây |
| Cloudflare Turnstile | *300 giây |
| hCaptcha | ~120 giây |
Đồng hồ tính giờ bắt đầu khi Cloudflare tạo mã thông báo - không phải khi CaptchaAI trả lại mã thông báo đó cho bạn và không phải khi bạn nhận được mã thông báo đó trong mã của mình.
Điều kiện cuộc đua
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
Đồng hồ đang điểm từ lúc 0:20. Bạn có thời gian đến khoảng 5:20 để gửi mã thông báo. Điều đó nghe có vẻ hào phóng nhưng hãy xem xét điều gì xảy ra trong quy trình làm việc thực tế:
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
Các kịch bản tình trạng cuộc đua phổ biến
1. Biểu mẫu nhiều bước
Các biểu mẫu yêu cầu nhiều trang trước khi gửi lần cuối:
Step 1: Fill personal info → Step 2: Fill address →
Step 3: Solve CAPTCHA → Step 4: Review → Step 5: Submit
Nếu CAPTCHA ở Bước 3 nhưng việc gửi diễn ra ở Bước 5 thì độ trễ giữa việc giải và gửi có thể vượt quá 5 phút.
2. Hàng đợi xử lý hàng loạt
Giải quyết các mã thông báo trước và sử dụng chúng sau:
# 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. Thử lại vòng lặp với mã thông báo cũ
Sử dụng lại mã thông báo sau khi gửi không thành công:
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
Ngăn chặn hết hạn
Chiến lược 1: Giải quyết đúng lúc
Chỉ yêu cầu mã thông báo khi bạn sẵn sàng gửi:
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
Chiến lược 2: Theo dõi tuổi token
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)
Chiến lược 3: Mã thông báo mới khi thử lại (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');
}
Phát hiện mã thông báo đã hết hạn
Trang web thường không cho bạn biết rõ ràng "mã thông báo đã hết hạn". Hãy tìm những tín hiệu sau:
| tín hiệu | chỉ định |
|---|---|
| HTTP 403 sau khi gửi mã thông báo | Mã thông báo không hợp lệ hoặc đã hết hạn |
| Chuyển hướng trở lại trang biểu mẫu | Xác minh mã thông báo không thành công |
| Thông báo lỗi: "xác minh không thành công" | Lỗi chung - có thể hết hạn |
| Trang thử thách xuất hiện lại | Mã thông báo bị từ chối, Cloudflare thử thách lại |
Ghi nhật ký để chẩn đoán
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)")
Hành vi tự động làm mới của Turnstile
Trong các luồng dựa trên trình duyệt, tiện ích Turnstile tự động làm mới mã thông báo trước khi chúng hết hạn. data-expired-callback kích hoạt khi mã thông báo hết hạn:
turnstile.render('#captcha', {
sitekey: '0x4AAAA...',
callback: (token) => {
console.log('New token:', token);
},
'expired-callback': () => {
console.log('Token expired — widget will auto-refresh');
}
});
Trong tự động hóa chỉ API (không có trình duyệt), bạn không được hưởng lợi từ tính năng tự động làm mới. Bạn phải tự mình quản lý việc làm mới mã thông báo.
Khắc phục sự cố
| Vấn đề | Nguyên nhân | Cách xử lý |
|---|---|---|
| Mã thông báo hoạt động trong thử nghiệm nhưng không hoạt động trong sản xuất | Quy trình sản xuất chậm hơn | Giải quyết kịp thời, không cần giải quyết trước |
| Lần gửi đầu tiên thành công, lần thử lại không thành công | Tái sử dụng mã thông báo đã tiêu thụ | Giải quyết một mã thông báo mới cho mỗi lần thử |
| Thất bại liên tục trên các biểu mẫu dài | Mã thông báo hết hạn trong quy trình nhiều bước | Chuyển việc giải CAPTCHA sang bước cuối cùng |
| Công việc hàng loạt có tỷ lệ thất bại cao | Mã thông báo được giải quyết hàng loạt sẽ hết hạn trước khi sử dụng | Giải quyết mã thông báo theo yêu cầu, không phải theo đợt |
Câu hỏi thường gặp
Tôi có thể kéo dài thời gian tồn tại của mã thông báo Turnstile không?
Không. Thời hạn hết hạn do Cloudflare đặt ra và không thể sửa đổi. Lựa chọn duy nhất của bạn là giải quyết một mã thông báo mới.
Giới hạn 300 giây chính xác đến mức nào?
Nó gần đúng. Cloudflare có thể điều chỉnh thời gian dựa trên cấu hình. Sử dụng 270 giây (4,5 phút) làm mức tối đa thực tế của bạn để có giới hạn an toàn.
Tôi có nên giải token sớm để tiết kiệm thời gian không?
Chỉ khi quy trình kiểm thử của bạn có thể tiêu thụ token trong vòng vài phút. Đối với batch QA, hãy giải token theo yêu cầu (just-in-time) thay vì lưu sẵn để tránh hết hạn.
bài viết liên quan
- Cloudflare Challenge Vs Phát hiện cửa quay
- So sánh Geetest và Cloudflare Turnstile
- Cloudflare Turnstile 403 Sau khi sửa mã thông báo
Các bước tiếp theo
Ngăn chặn hết hạn mã thông báo Turnstile —lấy khóa API CaptchaAI của bạnvà thực hiện giải quyết kịp thời với tỷ lệ thành công 100%.