{"record":{"id":"fbaa015e5b1e4f62","repo":"paascloud/paascloud-master","slug":"error-fbaa01","errorCode":null,"errorMessage":"操作频率过快","messagePattern":"操作频率过快","errorType":"validation","errorClass":"ValidateCodeException","httpStatus":400,"severity":"warning","filePath":"paascloud-common/paascloud-security-core/src/main/java/com/paascloud/security/core/validate/code/sms/SmsCodeProcessor.java","lineNumber":108,"sourceCode":"\t\t\tresult = SecurityResult.error(\"内部异常\", false);\n\t\t}\n\t\tString json = objectMapper.writeValueAsString(result);\n\t\tHttpServletResponse response = request.getResponse();\n\t\tresponse.setCharacterEncoding(\"UTF-8\");\n\t\tresponse.getWriter().write(json);\n\t}\n\n\tprivate void checkSendSmsCount(String mobile, String ipAddr) {\n\t\tString mobileSmsCountKey = RedisKeyUtil.getSendSmsCountKey(mobile, \"mobile\");\n\t\tString ipSmsCountKey = RedisKeyUtil.getSendSmsCountKey(ipAddr, \"ip\");\n\t\tString totalSmsCountKey = RedisKeyUtil.getSendSmsCountKey(\"total\", \"total\");\n\t\tString sendSmsRateKey = RedisKeyUtil.getSendSmsRateKey(ipAddr);\n\t\tSmsCodeProperties sms = securityProperties.getCode().getSms();\n\n\t\tInteger sendSmsRateCount = (Integer) redisTemplate.opsForValue().get(sendSmsRateKey);\n\t\tif (sendSmsRateCount != null) {\n\t\t\tlog.error(\"操作频率过快 ipAddr={}, mobile={}\", ipAddr, mobile);\n\t\t\tthrow new ValidateCodeException(\"操作频率过快\");\n\t\t} else {\n\t\t\tredisTemplate.opsForValue().set(sendSmsRateKey, 1, 1, TimeUnit.MINUTES);\n\t\t}\n\n\t\tInteger mobileSmsCount = (Integer) redisTemplate.opsForValue().get(mobileSmsCountKey);\n\t\tif (mobileSmsCount != null && mobileSmsCount > sms.getMobileMaxSendCount()) {\n\t\t\tlog.error(\"Mobile当天短信发送数上限 ipAddr={}, mobile={}\", ipAddr, mobile);\n\t\t\tthrow new ValidateCodeException(\"Mobile当天短信发送数上限\");\n\t\t} else {\n\t\t\tredisTemplate.opsForValue().set(mobileSmsCountKey, mobileSmsCount == null ? 1 : mobileSmsCount + 1, 1, TimeUnit.DAYS);\n\t\t}\n\t\tInteger ipSmsCount = (Integer) redisTemplate.opsForValue().get(ipSmsCountKey);\n\t\tif (ipSmsCount != null && ipSmsCount > sms.getIpMaxSendCount()) {\n\t\t\tlog.error(\"IP当天短信发送数上限 ipAddr={}, mobile={}\", ipAddr, mobile);\n\t\t\tthrow new ValidateCodeException(\"IP当天短信发送数上限\");\n\t\t} else {\n\t\t\tredisTemplate.opsForValue().set(ipSmsCountKey, ipSmsCount == null ? 1 : ipSmsCount + 1, 1, TimeUnit.DAYS);\n\t\t}","sourceCodeStart":90,"sourceCodeEnd":126,"githubUrl":"https://github.com/paascloud/paascloud-master/blob/781281a9503332ed3cef44ea618349d14230a127/paascloud-common/paascloud-security-core/src/main/java/com/paascloud/security/core/validate/code/sms/SmsCodeProcessor.java#L90-L126","documentation":"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 '操作频率过快'.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\nsendButton.onclick = () => requestSmsCode();\n// after\nsendButton.onclick = () => {\n  if (countdown > 0) return;\n  requestSmsCode();\n  startCountdown(60);\n};","handlingStrategy":"try-catch","validationCode":"if (Date.now() - lastSendAt < 60000) { alert('操作过于频繁，请稍后再试'); return; }","typeGuard":null,"tryCatchPattern":"try { smsProcessor.send(request); } catch (ValidateCodeException e) { if (e.getMessage().contains(\"操作频率过快\")) { return ResponseEntity.status(429).body(\"请一分钟后再试\"); } throw e; }","preventionTips":["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"],"tags":["validation-code","rate-limit","sms"],"backgroundTag":"rate-limit-exceeded","analyzedSha":"781281a9503332ed3cef44ea618349d14230a127","analyzedAt":"2026-09-10T10:59:02.070Z","contentChangedAt":"2026-09-10T10:59:02.070Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}