flipped-aurora/gin-vue-admin · warning

请求太过频繁,请稍后再试

Error message

请求太过频繁,请稍后再试

What it means

SetLimitWithTime is the rate-limit check behind the IP limiter middleware: it increments a counter in the runtime cache for a key and expires it after the window. When the incremented count exceeds the configured limit, it returns this error, which the middleware converts into an HTTP 429-style rejection. Cache errors deliberately fail open (logged, allowed) — this error is only the genuine over-limit case.

Source

Thrown at server/middleware/limit_ip.go:72

func DefaultLimit() gin.HandlerFunc {
	return LimitConfig{
		GenerationKey: DefaultGenerationKey,
		CheckOrMark:   DefaultCheckOrMark,
		Expire:        global.GVA_CONFIG.System.LimitTimeIP,
		Limit:         global.GVA_CONFIG.System.LimitCountIP,
	}.LimitWithTime()
}

// SetLimitWithTime 设置访问次数:窗口内计数到达 limit 即拒绝。
func SetLimitWithTime(key string, limit int, expiration time.Duration) error {
	count, err := global.GVA_CACHE.IncrementWithExpire(key, 1, expiration)
	if err != nil {
		// 运行时缓存异常:记录日志并 fail-open 放行
		logger.Bg().Mod("system").Err(err).Error("limit increment")
		return nil
	}
	if count > int64(limit) {
		return errors.New("请求太过频繁,请稍后再试")
	}
	return nil
}

// CacheCheckOrMark 基于 GVA_CACHE 的限流计数 超限返回错误 cache 异常 fail-open
func CacheCheckOrMark(key string, expire int, limit int) error {
	if global.GVA_CACHE == nil {
		return nil
	}
	n, err := global.GVA_CACHE.IncrementWithExpire(key, 1, time.Duration(expire)*time.Second)
	if err != nil {
		logger.Bg().Mod("system").Err(err).Error("limit")
		return nil // fail-open
	}
	if int(n) > limit {
		return errors.New("请求太过频繁,请稍后再试")
	}
	return nil

View on GitHub (pinned to 3136500ef3)

Solutions

  1. Wait for the time window to elapse — the counter expires automatically and traffic resumes
  2. Increase the route's limit / window configuration to match legitimate traffic volume
  3. If many legitimate users share one IP, raise the limit or key by user+IP instead of IP alone
  4. Stop/retry-with-backoff in client scripts so they stop tripping the limiter

Example fix

// before: unbounded retries in client
for { await fetch('/login', opts) }
// after: backoff on 429
for (let i = 0; i < 5; i++) {
  const res = await fetch('/login', opts)
  if (res.status !== 429) break
  await new Promise(r => setTimeout(r, 2 ** i * 1000))
}
Defensive patterns

Strategy: retry

Try / catch

resp, err := client.Do(req)
if err == nil && resp.StatusCode == 429 {
    retryAfter := parseRetryAfter(resp) // else exponential backoff
    time.Sleep(retryAfter)
    // retry with cap
}

Prevention

When it happens

Trigger: A client IP exceeding `limit` requests within `expire` seconds on a route wrapped with the limiter (e.g. via DefaultCheckOrMark). Bursty scripts, retries, or shared NAT/proxy IPs where many users share one IP exhaust the window quota.

Common situations: Load tests or scripts hammering a login endpoint; offices/campuses behind one egress IP; aggressive frontend polling; misconfigured (too low) limit for legitimate traffic.


AI-assisted analysis of flipped-aurora/gin-vue-admin@3136500ef3 (2026-08-31). Data as JSON: /api/errors/0afa8e2f7f8d51bb. Report an issue: GitHub.