fish2018/pansou · error
[ ] 搜索请求失败
Error message
[%s] 搜索请求失败: %w
What it means
searchImpl wraps any error from p.doRequestWithRetry(req, client) — the actual GET round trip to ahhhhfs.com including its built-in retries — as '[%s] 搜索请求失败'. All transport-level failures (DNS, TCP, TLS, proxy errors, timeouts from DefaultTimeout, and retries exhausted) surface here. Because retries are already applied, an error here means the request failed persistently.
Solutions
- Read the wrapped %w error to distinguish timeout (context deadline exceeded) from connect/DNS failures.
- Verify reachability with curl -v 'https://www.ahhhhfs.com/' from the same host.
- If the site requires a proxy on this network, configure it on the http.Client's Transport.
- Increase DefaultTimeout if requests are consistently timing out near the limit.
- Check whether doRequestWithRetry's retry count/backoff is adequate; harden it against connection resets.
Example fix
// before
resp, err := p.doRequestWithRetry(req, client)
if err != nil {
return nil, fmt.Errorf("[%s] 搜索请求失败: %w", p.Name(), err)
}
// after
resp, err := p.doRequestWithRetry(req, client)
if err != nil {
if errors.Is(err, context.DeadlineExceeded) {
return nil, fmt.Errorf("[%s] 搜索请求超时(>%s): %w", p.Name(), DefaultTimeout, err)
}
return nil, fmt.Errorf("[%s] 搜索请求失败(重试后仍失败): %w", p.Name(), err)
} Defensive patterns
Strategy: retry
Try / catch
results, err := p.Search(ctx, keyword)
if err != nil {
if errors.Is(err, context.DeadlineExceeded) {
// 超时: 增大 DefaultTimeout 或减少并发后重试
} else {
// 网络/代理故障: 换网络或配置代理后重试
}
} Prevention
- Give DefaultTimeout headroom for the site's typical latency.
- Configure the http.Client proxy when the network requires one.
- Rely on doRequestWithRetry but verify its retry count/backoff suits transient failures.
- Confirm the site domain is current and reachable from your host.
When it happens
Trigger: doRequestWithRetry returns err after exhausting its retry attempts: DNS resolution failure for www.ahhhhfs.com, connection refused/reset, TLS handshake failure, context deadline exceeded (DefaultTimeout), or proxy misconfiguration — all persisting across retries.
Common situations: The site (or its CDN) blocks the host's IP or region; the machine has no/broken internet or DNS; DefaultTimeout is too short for the site's response time; a required proxy is not configured; the domain changed and the old one no longer resolves.
Related errors
AI-assisted analysis of fish2018/pansou@beaa561337 (2026-09-07).
Data as JSON: /api/errors/f6a5911469709c8e.
Report an issue: GitHub.
Appendix: source
Thrown at plugin/ahhhhfs/ahhhhfs.go:181
// 3. 创建请求
req, err := http.NewRequestWithContext(ctx, "GET", searchURL, nil)
if err != nil {
return nil, fmt.Errorf("[%s] 创建请求失败: %w", p.Name(), err)
}
// 4. 设置完整的请求头(避免反爬虫)
req.Header.Set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36")
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("Upgrade-Insecure-Requests", "1")
req.Header.Set("Cache-Control", "max-age=0")
req.Header.Set("Referer", "https://www.ahhhhfs.com/")
// 5. 发送请求(带重试机制)
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 != 200 {
return nil, fmt.Errorf("[%s] 搜索请求返回状态码: %d", p.Name(), resp.StatusCode)
}
// 6. 解析搜索结果页面
doc, err := goquery.NewDocumentFromReader(resp.Body)
if err != nil {
return nil, fmt.Errorf("[%s] 解析搜索页面失败: %w", p.Name(), err)
}
// 7. 提取搜索结果
var results []model.SearchResult
var wg sync.WaitGroup
var mu sync.Mutex
semaphore := make(chan struct{}, MaxConcurrency)View on GitHub (pinned to beaa561337)