fish2018/pansou · warning
HTTP状态码
Error message
HTTP状态码: %d
What it means
Inside doRequestWithRetry, each attempt that completes without a transport error but with a non-200 status closes the body and stores "HTTP状态码: %d" as lastErr, then retries. This is the internal error describing why an attempt was rejected.
Solutions
- This error is internal: it surfaces wrapped by the retry-exhausted error (index 273); read the status code from the wrapped message
- Add longer backoff between retries to survive 429 windows
- Use proxies / rotate egress IPs if the site is blocking yours
- Check target site health independently (browser/curl) to rule out an outage
- Consider treating 4xx client errors as non-retryable to fail fast
Example fix
// before
resp.Body.Close()
lastErr = fmt.Errorf("HTTP状态码: %d", resp.StatusCode)
// after
resp.Body.Close()
lastErr = fmt.Errorf("HTTP状态码: %d", resp.StatusCode)
if resp.StatusCode == http.StatusForbidden || resp.StatusCode == http.StatusTooManyRequests {
time.Sleep(time.Duration(1<<i) * time.Second) // exponential backoff
} Defensive patterns
Strategy: retry
Validate before calling
resp, err := http.Get(targetURL)
if err == nil && resp.StatusCode == http.StatusTooManyRequests {
// wait out the rate-limit window before calling the plugin
} Try / catch
// this is an internal retry-loop error; consume it via the final wrapped error
if _, err := plugin.Search(kw); err != nil {
var statusErr error
if errors.Unwrap(err) != nil { statusErr = errors.Unwrap(err) }
log.Printf("retries exhausted, last cause: %v", statusErr)
} Prevention
- Keep upstream QPS low enough that each attempt succeeds within maxRetries
- Add exponential backoff instead of fixed 100ms sleeps
- Pre-check upstream health before bursts of requests
- Use proxies when the target site blocks datacenter IPs
When it happens
Trigger: client.Do succeeds but resp.StatusCode != http.StatusOK on every retry attempt of doRequestWithRetry, called from searchAtBase or fetchDetailLinksAndImages (e.g. persistent 403/429/503 from the huban site).
Common situations: Persistent rate limiting (429) during burst scraping, IP banned by the target site, WAF/Cloudflare challenge, site-side 5xx outage across all retries.
Related errors
AI-assisted analysis of fish2018/pansou@beaa561337 (2026-09-07).
Data as JSON: /api/errors/a31218f9632b1a0c.
Report an issue: GitHub.
Appendix: source
Thrown at plugin/huban/huban.go:618
return matches[1]
}
return ""
}
// doRequestWithRetry 带重试的HTTP请求
func (p *HubanAsyncPlugin) doRequestWithRetry(req *http.Request, client *http.Client) (*http.Response, error) {
maxRetries := 2
var lastErr error
for i := 0; i < maxRetries; i++ {
resp, err := client.Do(req)
if err == nil {
if resp.StatusCode == http.StatusOK {
return resp, nil
}
resp.Body.Close()
lastErr = fmt.Errorf("HTTP状态码: %d", resp.StatusCode)
} else {
lastErr = err
}
if req.Context().Err() != nil {
return nil, req.Context().Err()
}
// 快速重试:只等待很短时间
if i < maxRetries-1 {
time.Sleep(100 * time.Millisecond)
}
}
return nil, fmt.Errorf("[%s] 请求失败,重试%d次后仍失败: %w", p.Name(), maxRetries, lastErr)
}
// GetPerformanceStats 获取性能统计信息
func (p *HubanAsyncPlugin) GetPerformanceStats() map[string]interface{} {View on GitHub (pinned to beaa561337)