如何为重试函数设置过期时间?验证码重获功能实现
Got it, let's break this down into two clear parts: handling the expired captcha prompt with a retry option, and setting expiration limits for retry functions. Here's how you can tackle both effectively:
First, you need to track the captcha's expiration from the moment it's generated, then build logic to trigger the retry prompt when it's no longer valid. Here's a step-by-step approach:
- Store expiration data with the captcha: When your backend generates a captcha, save not just the captcha value but also an expiration timestamp (e.g., current time + 120 seconds for 2-minute validity). Use a cache like Redis (for production) or a session store, linked to a unique user/session ID.
- Frontend prompt: proactive or reactive:
- Proactive: Start a 2-minute timer as soon as the captcha loads. When it hits zero, hide the captcha and show a "Captcha expired, click to re-obtain" message that's clickable.
- Reactive: If the user tries to submit an expired captcha, your backend returns an error like
{"error": "captcha_expired"}—the frontend then switches to the retry prompt.
- Refresh on retry: When the user clicks the retry button, send a request to your captcha generation endpoint again. Clear the old captcha data from storage, generate a new one with a fresh expiration, and render it to the user.
Example Code Snippets
Backend (Python/Flask):
import time from flask import Flask, request, jsonify app = Flask(__name__) # Use Redis in production instead of this in-memory dict captcha_storage = {} @app.route('/generate-captcha') def generate_captcha(): session_id = request.args.get('session_id') captcha_value = "XYZ123" # Replace with your actual captcha generator expiration_time = int(time.time()) + 120 # 2 minutes from now captcha_storage[session_id] = {"value": captcha_value, "expires": expiration_time} return jsonify({"captcha": captcha_value, "expires_at": expiration_time}) @app.route('/verify-captcha', methods=['POST']) def verify_captcha(): data = request.get_json() session_id = data['session_id'] submitted_captcha = data['captcha'] if session_id not in captcha_storage: return jsonify({"error": "captcha_not_found"}), 400 captcha_data = captcha_storage[session_id] if int(time.time()) > captcha_data['expires']: del captcha_storage[session_id] # Clean up expired data return jsonify({"error": "captcha_expired"}), 400 if submitted_captcha == captcha_data['value']: del captcha_storage[session_id] return jsonify({"success": True}) else: return jsonify({"error": "invalid_captcha"}), 400
Frontend (JavaScript):
let captchaTimer; const sessionId = "user-session-123"; // Get this from your session system function fetchNewCaptcha() { // Clear existing timer to avoid duplicate prompts if (captchaTimer) clearTimeout(captchaTimer); fetch(`/generate-captcha?session_id=${sessionId}`) .then(res => res.json()) .then(data => { const captchaDisplay = document.getElementById('captcha-display'); const retryPrompt = document.getElementById('retry-prompt'); captchaDisplay.textContent = data.captcha; captchaDisplay.style.display = 'block'; retryPrompt.style.display = 'none'; // Set timer to show expiration after 2 minutes const timeLeft = (data.expires_at - Date.now() / 1000) * 1000; captchaTimer = setTimeout(() => { captchaDisplay.style.display = 'none'; retryPrompt.style.display = 'block'; }, timeLeft); }); } // Load initial captcha on page load fetchNewCaptcha(); // Retry button click handler document.getElementById('retry-btn').addEventListener('click', fetchNewCaptcha);
If you're building retry logic (e.g., retrying captcha submission if it fails, or retrying generation if the request times out), you need to define an overall expiration window so retries don't run indefinitely. Here's how to implement a reusable retry wrapper:
Reusable Retry Decorator (Python Example)
import time from functools import wraps def retry_with_expiry(max_retries=3, total_expiry=120, base_delay=5): """Decorator to retry a function until success or total expiry is reached.""" def decorator(func): @wraps(func) def wrapper(*args, **kwargs): start_time = time.time() attempt = 0 while attempt < max_retries: # Check if we've exceeded the total expiration window if time.time() - start_time > total_expiry: raise TimeoutError(f"Retry expired: {func.__name__} took longer than {total_expiry}s") try: return func(*args, **kwargs) except Exception as e: print(f"Attempt {attempt + 1} failed: {str(e)}. Retrying in {base_delay}s...") attempt += 1 time.sleep(base_delay) # Optional: Use exponential backoff (e.g., base_delay * 2 ** attempt) raise Exception(f"{func.__name__} failed after {max_retries} retries") return wrapper return decorator # Usage example @retry_with_expiry(max_retries=3, total_expiry=120, base_delay=10) def submit_captcha(session_id, captcha_value): response = requests.post('/verify-captcha', json={"session_id": session_id, "captcha": captcha_value}) response.raise_for_status() # Trigger error for 4xx/5xx responses return response.json() # Use the function with error handling try: result = submit_captcha("user-session-123", "XYZ123") print("Captcha verified successfully!") except TimeoutError: print("Retry window expired. Please refresh and try again.") except Exception: print("Captcha verification failed after all retries.")
Key Takeaways for Retry Expiration
- Track total elapsed time: Start a timer when the retry process begins, and stop retrying if it exceeds your limit (match it to the captcha's 2-minute validity for consistency).
- Smart delays: Use exponential backoff instead of fixed delays to reduce server load—e.g., 5s, 10s, 20s between retries.
- Clear error signaling: Raise distinct errors for expiration vs. failed attempts so your frontend can show the right message to users.
内容的提问来源于stack exchange,提问作者cbos93

