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

  1. This error is internal: it surfaces wrapped by the retry-exhausted error (index 273); read the status code from the wrapped message
  2. Add longer backoff between retries to survive 429 windows
  3. Use proxies / rotate egress IPs if the site is blocking yours
  4. Check target site health independently (browser/curl) to rule out an outage
  5. 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

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)