paascloud/paascloud-master · warning · ValidateCodeException
操作频率过快
Error message
操作频率过快
What it means
SmsCodeProcessor.checkSendSmsCount enforces send-rate limiting before dispatching an SMS. If a rate key for the requester's IP exists in Redis (set for 1 minute after each send), the send is refused with ValidateCodeException '操作频率过快'.
Solutions
- Wait 1 minute (rate window) before requesting again
- Debounce/disable the send button on the client after the first click and show a countdown
- Tune rate limits via securityProperties.getCode().getSms() (send rate interval, mobileMaxSendCount)
- Catch ValidateCodeException and surface a friendly 'please retry later' message
Example fix
// before
sendButton.onclick = () => requestSmsCode();
// after
sendButton.onclick = () => {
if (countdown > 0) return;
requestSmsCode();
startCountdown(60);
}; Defensive patterns
Strategy: try-catch
Validate before calling
if (Date.now() - lastSendAt < 60000) { alert('操作过于频繁,请稍后再试'); return; } Try / catch
try { smsProcessor.send(request); } catch (ValidateCodeException e) { if (e.getMessage().contains("操作频率过快")) { return ResponseEntity.status(429).body("请一分钟后再试"); } throw e; } Prevention
- Client-side countdown timer after each send
- Disable double-click on the send button
- Tune SMS rate properties for shared-IP environments
- Alert on abnormal send volume from single IPs
When it happens
Trigger: Requesting an SMS code more than once within the configured rate window (default 1 minute per IP), or exceeding mobileMaxSendCount within its window; raised from send() via checkSendSmsCount.
Common situations: Users double-clicking the send button; automated scripts hammering the endpoint; shared NAT/office IP causing legitimate distinct users to hit the same IP counter; retry loops in a buggy frontend.
Related errors
AI-assisted analysis of paascloud/paascloud-master@781281a950 (2026-09-10).
Data as JSON: /api/errors/fbaa015e5b1e4f62.
Report an issue: GitHub.
Appendix: source
Thrown at paascloud-common/paascloud-security-core/src/main/java/com/paascloud/security/core/validate/code/sms/SmsCodeProcessor.java:108
result = SecurityResult.error("内部异常", false);
}
String json = objectMapper.writeValueAsString(result);
HttpServletResponse response = request.getResponse();
response.setCharacterEncoding("UTF-8");
response.getWriter().write(json);
}
private void checkSendSmsCount(String mobile, String ipAddr) {
String mobileSmsCountKey = RedisKeyUtil.getSendSmsCountKey(mobile, "mobile");
String ipSmsCountKey = RedisKeyUtil.getSendSmsCountKey(ipAddr, "ip");
String totalSmsCountKey = RedisKeyUtil.getSendSmsCountKey("total", "total");
String sendSmsRateKey = RedisKeyUtil.getSendSmsRateKey(ipAddr);
SmsCodeProperties sms = securityProperties.getCode().getSms();
Integer sendSmsRateCount = (Integer) redisTemplate.opsForValue().get(sendSmsRateKey);
if (sendSmsRateCount != null) {
log.error("操作频率过快 ipAddr={}, mobile={}", ipAddr, mobile);
throw new ValidateCodeException("操作频率过快");
} else {
redisTemplate.opsForValue().set(sendSmsRateKey, 1, 1, TimeUnit.MINUTES);
}
Integer mobileSmsCount = (Integer) redisTemplate.opsForValue().get(mobileSmsCountKey);
if (mobileSmsCount != null && mobileSmsCount > sms.getMobileMaxSendCount()) {
log.error("Mobile当天短信发送数上限 ipAddr={}, mobile={}", ipAddr, mobile);
throw new ValidateCodeException("Mobile当天短信发送数上限");
} else {
redisTemplate.opsForValue().set(mobileSmsCountKey, mobileSmsCount == null ? 1 : mobileSmsCount + 1, 1, TimeUnit.DAYS);
}
Integer ipSmsCount = (Integer) redisTemplate.opsForValue().get(ipSmsCountKey);
if (ipSmsCount != null && ipSmsCount > sms.getIpMaxSendCount()) {
log.error("IP当天短信发送数上限 ipAddr={}, mobile={}", ipAddr, mobile);
throw new ValidateCodeException("IP当天短信发送数上限");
} else {
redisTemplate.opsForValue().set(ipSmsCountKey, ipSmsCount == null ? 1 : ipSmsCount + 1, 1, TimeUnit.DAYS);
}View on GitHub (pinned to 781281a950)