fix: 修复验证码请求429错误

问题:
- 短时间内多次请求验证码触发限流(429 Too Many Requests)

修复:
- 后端:验证码最小请求间隔从3秒改为1秒
- 前端:添加2秒防抖,避免重复请求
- 前端:429错误时保留已有验证码图片

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2025-11-28 14:06:23 +08:00
parent 9d36063e09
commit 4f1a1ec97c
2 changed files with 28 additions and 32 deletions

View File

@@ -755,7 +755,7 @@ const fileListLimiter = new RateLimiter({
}); });
// 验证码最小请求间隔控制 // 验证码最小请求间隔控制
const CAPTCHA_MIN_INTERVAL = 3000; // 3 const CAPTCHA_MIN_INTERVAL = 1000; // 1
const captchaLastRequest = new TTLCache(15 * 60 * 1000); // 15分钟自动清理 const captchaLastRequest = new TTLCache(15 * 60 * 1000); // 15分钟自动清理
// 验证码防刷中间件 // 验证码防刷中间件

View File

@@ -622,52 +622,48 @@ handleDragLeave(e) {
} }
}, },
// 刷新验证码(登录 // 通用验证码加载函数(带防抖
async refreshCaptcha() { async loadCaptcha(targetField) {
// 防抖2秒内不重复请求
const now = Date.now();
if (this._lastCaptchaTime && (now - this._lastCaptchaTime) < 2000) {
console.log('[验证码] 请求过于频繁,跳过');
return;
}
this._lastCaptchaTime = now;
try { try {
const response = await axios.get(`${this.apiBase}/api/captcha?t=${Date.now()}`, { const response = await axios.get(`${this.apiBase}/api/captcha?t=${now}`, {
responseType: 'blob' responseType: 'blob'
}); });
this.captchaUrl = URL.createObjectURL(response.data); this[targetField] = URL.createObjectURL(response.data);
} catch (error) { } catch (error) {
console.error('获取验证码失败:', error); console.error('获取验证码失败:', error);
// 如果是429错误不清除已有验证码
if (error.response?.status !== 429) {
this[targetField] = '';
}
} }
}, },
// 刷新验证码(登录)
refreshCaptcha() {
this.loadCaptcha('captchaUrl');
},
// 刷新注册验证码 // 刷新注册验证码
async refreshRegisterCaptcha() { refreshRegisterCaptcha() {
try { this.loadCaptcha('registerCaptchaUrl');
const response = await axios.get(`${this.apiBase}/api/captcha?t=${Date.now()}`, {
responseType: 'blob'
});
this.registerCaptchaUrl = URL.createObjectURL(response.data);
} catch (error) {
console.error('获取验证码失败:', error);
}
}, },
// 刷新忘记密码验证码 // 刷新忘记密码验证码
async refreshForgotPasswordCaptcha() { refreshForgotPasswordCaptcha() {
try { this.loadCaptcha('forgotPasswordCaptchaUrl');
const response = await axios.get(`${this.apiBase}/api/captcha?t=${Date.now()}`, {
responseType: 'blob'
});
this.forgotPasswordCaptchaUrl = URL.createObjectURL(response.data);
} catch (error) {
console.error('获取验证码失败:', error);
}
}, },
// 刷新重发验证邮件验证码 // 刷新重发验证邮件验证码
async refreshResendVerifyCaptcha() { refreshResendVerifyCaptcha() {
try { this.loadCaptcha('resendVerifyCaptchaUrl');
const response = await axios.get(`${this.apiBase}/api/captcha?t=${Date.now()}`, {
responseType: 'blob'
});
this.resendVerifyCaptchaUrl = URL.createObjectURL(response.data);
} catch (error) {
console.error('获取验证码失败:', error);
}
}, },
async resendVerification() { async resendVerification() {