fish2018/pansou · warning
[ ] 请求被限流
Error message
[%s] 请求被限流
What it means
The yuhuage upstream returned HTTP 429 Too Many Requests. searchImpl sets the rateLimited flag for 60 seconds (subsequent searches fail fast with "rate limited") and returns "[%s] 请求被限流" for the current call. It signals the site is actively throttling this client.
Solutions
- Back off — the plugin already pauses new searches for 60s; avoid hammering retries meanwhile.
- Reduce request concurrency or add a global rate limiter in front of the plugin.
- Distribute outbound traffic across proxies/IPs if volume is legitimately high.
- Skip this plugin for the throttle window in aggregation logic instead of surfacing errors to users.
Example fix
// before
if resp.StatusCode == 429 {
atomic.StoreInt32(&p.rateLimited, 1)
go func() {
time.Sleep(60 * time.Second)
atomic.StoreInt32(&p.rateLimited, 0)
}()
return nil, fmt.Errorf("[%s] 请求被限流", p.Name())
}
// after
if resp.StatusCode == 429 {
atomic.StoreInt32(&p.rateLimited, 1)
if retryAfter := resp.Header.Get("Retry-After"); retryAfter != "" {
if secs, e := strconv.Atoi(retryAfter); e == nil && secs > 0 && secs <= 600 {
rateLimitResetAt = time.Now().Add(time.Duration(secs) * time.Second)
}
}
return nil, fmt.Errorf("[%s] 请求被限流", p.Name())
} Defensive patterns
Strategy: retry
Validate before calling
// Pace calls proactively to avoid 429:
if time.Since(lastCall) < 1*time.Second {
time.Sleep(time.Second - time.Since(lastCall))
} Try / catch
results, err := plugin.Search(keyword, ext)
if err != nil {
if strings.Contains(err.Error(), "请求被限流") {
time.Sleep(65 * time.Second)
results, err = plugin.Search(keyword, ext)
}
} Prevention
- Respect the 60s cooldown; don't retry immediately after 429.
- Add a global rate limiter in front of the plugin.
- Honor Retry-After semantics if you add them client-side.
When it happens
Trigger: A search request completed and resp.StatusCode == 429; triggered by sending too many requests in a short window from the same IP.
Common situations: Bursty search traffic from many users; multiple pansou instances sharing one outbound IP; the site tightened its rate limits.
Related errors
AI-assisted analysis of fish2018/pansou@beaa561337 (2026-09-07).
Data as JSON: /api/errors/3dcb6bcefea856a8.
Report an issue: GitHub.
Appendix: source
Thrown at plugin/yuhuage/yuhuage.go:109
req.Header.Set("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8")
req.Header.Set("Accept-Language", "zh-CN,zh;q=0.9,en;q=0.8")
req.Header.Set("Connection", "keep-alive")
req.Header.Set("Referer", BaseURL+"/")
// 发送HTTP请求
resp, err := p.doRequestWithRetry(req, client)
if err != nil {
return nil, fmt.Errorf("[%s] 搜索请求失败: %w", p.Name(), err)
}
defer resp.Body.Close()
if resp.StatusCode == 429 {
atomic.StoreInt32(&p.rateLimited, 1)
go func() {
time.Sleep(60 * time.Second)
atomic.StoreInt32(&p.rateLimited, 0)
}()
return nil, fmt.Errorf("[%s] 请求被限流", p.Name())
}
if resp.StatusCode != 200 {
return nil, fmt.Errorf("[%s] HTTP错误: %d", p.Name(), resp.StatusCode)
}
// 读取响应
body, err := io.ReadAll(resp.Body)
if err != nil {
return nil, fmt.Errorf("[%s] 读取响应失败: %w", p.Name(), err)
}
// 解析搜索结果
results, err := p.parseSearchResults(string(body))
if err != nil {
return nil, err
}
View on GitHub (pinned to beaa561337)