fish2018/pansou · error
请求失败
Error message
请求失败: %w
What it means
fetchPage in the bixin plugin wraps any error from http.Client.Do after exhausting all retry attempts (p.retries). It means the HTTP transport itself failed — connection refused, DNS failure, TLS handshake error, or timeout — and retries (500ms apart) did not help. The original transport error is preserved via %w for errors.Is/As inspection.
Solutions
- Check basic connectivity to the bixin API host (curl the endpoint) to rule out network/firewall issues.
- Inspect the wrapped error with errors.Is/As (e.g. net.Error timeout, *url.Error) to identify the transport root cause.
- Increase p.retries or backoff duration to tolerate transient network blips.
- Verify proxy environment variables (HTTP_PROXY/HTTPS_PROXY) and DNS resolution.
Example fix
// before
return nil, false, fmt.Errorf("请求失败: %w", err)
// after
var netErr net.Error
if errors.As(err, &netErr) && netErr.Timeout() {
return nil, false, fmt.Errorf("请求超时(已重试%d次): %w", p.retries, err)
}
return nil, false, fmt.Errorf("请求失败: %w", err) Defensive patterns
Strategy: retry
Validate before calling
// caller-side preflight
req, _ := http.NewRequest("GET", apiURL, nil)
resp, err := http.DefaultClient.Do(req)
if err != nil { log.Printf("bixin API unreachable: %v", err) } else { resp.Body.Close() } Try / catch
results, err := plugin.Search(ctx, keyword)
if err != nil {
var netErr net.Error
if errors.As(err, &netErr) && netErr.Timeout() {
// degrade gracefully: return cached or empty results
} else if errors.Is(err, context.DeadlineExceeded) {
// surface 'search timed out' to user
}
} Prevention
- Check network/proxy configuration before deploying scrapers
- Set a sane retries count with exponential backoff rather than fixed 500ms
- Monitor DNS/firewall changes in the deployment environment
- Log the wrapped root cause, not just the wrapper message
When it happens
Trigger: client.Do(req) returns a non-nil err on the final retry iteration (i == p.retries) inside fetchPage; e.g. the bixin API host is unreachable, DNS fails, TLS fails, or the request times out.
Common situations: API host blocked or offline, corporate proxy/firewall blocking outbound HTTPS, DNS misconfiguration, network outage, or too-low p.retries for a flaky network.
Related errors
AI-assisted analysis of fish2018/pansou@beaa561337 (2026-09-07).
Data as JSON: /api/errors/cd520b6ab2150723.
Report an issue: GitHub.
Appendix: source
Thrown at plugin/bixin/bixin.go:207
req.Header.Set("User-Agent", getRandomUA())
req.Header.Set("X-Forwarded-For", generateRandomIP())
req.Header.Set("Accept", "application/json, text/plain, */*")
req.Header.Set("Accept-Language", "zh-CN,zh;q=0.9,en;q=0.8")
req.Header.Set("Connection", "keep-alive")
req.Header.Set("Sec-Fetch-Dest", "empty")
req.Header.Set("Sec-Fetch-Mode", "cors")
req.Header.Set("Sec-Fetch-Site", "same-origin")
var resp *http.Response
var responseBody []byte
// 重试逻辑
for i := 0; i <= p.retries; i++ {
// 发送请求
resp, err = client.Do(req)
if err != nil {
if i == p.retries {
return nil, false, fmt.Errorf("请求失败: %w", err)
}
time.Sleep(500 * time.Millisecond)
continue
}
defer resp.Body.Close()
// 读取响应体
responseBody, err = io.ReadAll(resp.Body)
if err != nil {
if i == p.retries {
return nil, false, fmt.Errorf("读取响应失败: %w", err)
}
time.Sleep(500 * time.Millisecond)
continue
}
// 状态码检查View on GitHub (pinned to beaa561337)