{"record":{"id":"80f775f33605f0a3","repo":"paascloud/paascloud-master","slug":"error-80f775","errorCode":null,"errorMessage":"当天短信发送数上限","messagePattern":"当天短信发送数上限","errorType":"error_code","errorClass":"ValidateCodeException","httpStatus":null,"severity":"error","filePath":"paascloud-common/paascloud-security-core/src/main/java/com/paascloud/security/core/validate/code/sms/SmsCodeProcessor.java","lineNumber":130,"sourceCode":"\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}\n\t\tInteger totalSmsCount = (Integer) redisTemplate.opsForValue().get(totalSmsCountKey);\n\t\tif (totalSmsCount != null && totalSmsCount > sms.getTotalMaxSendCount()) {\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(totalSmsCountKey, totalSmsCount == null ? 1 : totalSmsCount + 1, 1, TimeUnit.DAYS);\n\t\t}\n\t}\n\n\tprivate String getRemoteAddr(HttpServletRequest request) {\n\t\tString ipAddress = request.getHeader(X_FORWARDED_FOR);\n\t\tif (ipAddress == null || ipAddress.length() == 0 || UNKNOWN.equalsIgnoreCase(ipAddress)) {\n\t\t\tipAddress = request.getHeader(PROXY_CLIENT_IP);\n\t\t}\n\t\tif (ipAddress == null || ipAddress.length() == 0 || UNKNOWN.equalsIgnoreCase(ipAddress)) {\n\t\t\tipAddress = request.getHeader(WL_PROXY_CLIENT_IP);\n\t\t}\n\t\tif (ipAddress == null || ipAddress.length() == 0 || UNKNOWN.equalsIgnoreCase(ipAddress)) {\n\t\t\tipAddress = request.getRemoteAddr();\n\t\t\tif (LOCALHOST_IP.equals(ipAddress) || LOCALHOST_IP_16.equals(ipAddress)) {\n\t\t\t\t//根据网卡取本机配置的IP\n\t\t\t\tInetAddress inet = null;","sourceCodeStart":112,"sourceCodeEnd":148,"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#L112-L148","documentation":"checkSendSmsCount finally enforces a global daily SMS quota: it reads totalSmsCountKey from Redis and throws ValidateCodeException('当天短信发送数上限') when the total count exceeds sms.getTotalMaxSendCount(). This caps overall SMS volume for the whole system per day, protecting the SMS provider account from cost overruns and exhaustion.","triggerScenarios":"Any SMS send (send -> checkSendSmsCount) once the system-wide Redis day-counter exceeds smsProperties.getTotalMaxSendCount(); affects all users, not just one mobile or IP.","commonSituations":"SMS provider quota reached for the day (expected behavior at scale); totalMaxSendCount configured too low for production traffic; a spike/abuse event consumed the daily budget; staging shared Redis with production counters.","solutions":["Raise sms.getTotalMaxSendCount() to match your SMS provider's actual daily plan","Verify the Redis totalSmsCountKey TTL/reset semantics; consider resetting at midnight if counters drift","Delete the Redis total key to restore service in an emergency (testing only)","Alert/monitor on the total counter so ops can raise limits or top up the SMS account before exhaustion"],"exampleFix":"// before: default limit too low for prod traffic\nsms:\n  total-max-send-count: 1000\n// after: sized to provider plan\nsms:\n  total-max-send-count: 100000","handlingStrategy":"try-catch","validationCode":"Integer total = (Integer) redisTemplate.opsForValue().get(totalSmsCountKey);\nif (total != null && total > totalMaxSendCount) {\n    // disable send-code UI system-wide\n}","typeGuard":null,"tryCatchPattern":"try {\n    smsCodeSender.send(mobile);\n} catch (ValidateCodeException e) {\n    alertOps(\"System-wide SMS daily quota exhausted\");\n    return Result.error(503, \"短信服务今日额度已用尽\");\n}","preventionTips":["Size totalMaxSendCount to your SMS provider's daily plan with headroom","Alert on the total counter at e.g. 80% so you can top up the SMS account before exhaustion","Keep staging and production Redis isolated so test traffic doesn't consume the production quota","Log which flows consumed the quota to detect abuse or runaway loops"],"tags":["rate-limit","sms","redis","quota"],"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"}