fish2018/pansou · error
HTTP状态码
Error message
HTTP状态码: %d
What it means
Internal retry bookkeeping error in doRequestWithRetry: the HTTP request succeeded but the server returned a status code other than 200. This value becomes lastErr and is surfaced wrapped by the '重试 N 次后仍然失败' error. It is not usually seen directly by callers, only as the wrapped cause.
Solutions
- Check the reported status code: 403/429 usually means auth or rate limiting; 5xx means the upstream server is having issues.
- Update cookies/User-Agent for the feikuai site if the site tightened bot detection.
- Increase backoff between retries or reduce request frequency.
- Verify the target URL is still valid (site may have moved, returning 404).
Defensive patterns
Strategy: retry
Validate before calling
resp, err := http.Head(targetURL)
if err == nil && resp.StatusCode >= 400 {
log.Printf("upstream currently returns %d; skipping attempt", resp.StatusCode)
} Try / catch
results, err := searchImpl(keyword)
if err != nil {
var wrapped interface{ Unwrap() error }
if errors.As(err, &retryErr{}) {
log.Printf("upstream status issue: %v", err)
return backoffThenRetryOrFallback()
}
return err
} Prevention
- Respect rate limits; add jittered backoff between requests
- Keep cookies and User-Agent current to avoid 403/429
- Alert on sustained non-200 status codes for the upstream
- Cache last good results to serve during upstream incidents
When it happens
Trigger: doRequestWithRetry: client.Do succeeded but resp.StatusCode != 200 on every attempt; the last such status is stored as lastErr.
Common situations: Target site rate-limiting (429), temporary 502/503 from CDN, 403 due to missing/rotated cookies, bot detection returning 4xx/5xx.
Related errors
AI-assisted analysis of fish2018/pansou@beaa561337 (2026-09-07).
Data as JSON: /api/errors/32aa91ff9c6045f3.
Report an issue: GitHub.
Appendix: source
Thrown at plugin/feikuai/feikuai.go:538
var lastErr error
for i := 0; i < maxRetries; i++ {
if i > 0 {
// 指数退避
backoff := time.Duration(1<<uint(i-1)) * 200 * time.Millisecond
time.Sleep(backoff)
}
// 克隆请求避免并发问题
reqClone := req.Clone(req.Context())
resp, err := client.Do(reqClone)
if err == nil {
if resp.StatusCode == 200 {
return resp, nil
}
resp.Body.Close()
lastErr = fmt.Errorf("HTTP状态码: %d", resp.StatusCode)
} else {
lastErr = err
}
}
return nil, fmt.Errorf("[%s] 重试 %d 次后仍然失败: %w", p.Name(), maxRetries, lastErr)
}
View on GitHub (pinned to beaa561337)