fish2018/pansou · error
[ ] 搜索请求失败
Error message
[%s] 搜索请求失败: %w
What it means
ClmaoPlugin.searchPage wraps a failure from p.doRequestWithRetry(req, client), the retrying HTTP call that performs the GET to the clmao search endpoint. The error means every retry attempt failed at the transport level (connection error, timeout, TLS handshake, context deadline). No response body is available, so no status check or parsing happens.
Solutions
- Unwrap the chain (this wraps doRequestWithRetry's "请求失败,已重试%d次" error, which wraps the last transport error) to see the root cause.
- Test connectivity to the site with curl from the same host.
- Increase TimeoutSeconds if timeouts dominate, or reduce MaxRetries to fail fast when the site is clearly unreachable.
- Update request headers/cookies in setRequestHeaders if the site started rejecting the client.
- Add jittered/exponential backoff if the failures correlate with rate limiting.
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] 搜索请求超时(TimeoutSeconds=%d): %w", p.Name(), TimeoutSeconds, err)
}
return nil, fmt.Errorf("[%s] 搜索请求失败: %w", p.Name(), err)
} Defensive patterns
Strategy: retry
Validate before calling
func endpointHealthy(client *http.Client, url string) bool {
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
req, _ := http.NewRequestWithContext(ctx, http.MethodHead, url, nil)
resp, err := client.Do(req)
return err == nil && resp != nil
} Try / catch
results, err := p.searchPage(client, keyword, page)
if err != nil {
var netErr net.Error
if errors.As(err, &netErr) && netErr.Timeout() {
time.Sleep(backoff)
return p.searchPage(client, keyword, page) // single manual retry
}
return nil, err
} Prevention
- Retry transient failures at the caller level with backoff.
- Ensure TimeoutSeconds exceeds worst-case response time of the site.
- Check environment connectivity/DNS before bulk operations.
- Keep browser-like headers to avoid connection drops from anti-bot layers.
When it happens
Trigger: searchPage calls p.doRequestWithRetry(req, client); after MaxRetries attempts (each with linear sleep backoff) no response was obtained — network unreachable, DNS failure, connection reset, or the per-request context (TimeoutSeconds) expired — and the wrapped retry error is re-wrapped with the plugin name.
Common situations: The clmao site is down, blocking the client (anti-bot dropping connections), or slow enough that TimeoutSeconds expires on every attempt; local network/proxy problems; DNS resolution failures in containerized environments.
Understand the failure class
Background: 'Something went wrong' / 'Request failed (500)' / 'HTTP error! status: 404' — what failed HTTP requests actually mean and how to find the real cause — this error's family across 28 libraries.
Related errors
AI-assisted analysis of fish2018/pansou@beaa561337 (2026-09-07).
Data as JSON: /api/errors/a001dd7d7585e97f.
Report an issue: GitHub.
Appendix: source
Thrown at plugin/clmao/clmao.go:188
}
// 创建带超时的上下文
ctx, cancel := context.WithTimeout(context.Background(), TimeoutSeconds*time.Second)
defer cancel()
// 创建请求
req, err := http.NewRequestWithContext(ctx, "GET", searchURL, nil)
if err != nil {
return nil, fmt.Errorf("[%s] 创建请求失败: %w", p.Name(), err)
}
// 设置请求头
p.setRequestHeaders(req)
// 发送HTTP请求
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)
}
// 读取响应体内容
body, err := io.ReadAll(resp.Body)
if err != nil {
return nil, fmt.Errorf("[%s] 读取响应失败: %w", p.Name(), err)
}
decodedHTML := decodeModernPayload(string(body))
if decodedHTML != string(body) {
if modernResults := p.parseModernSearchResults(client, decodedHTML); len(modernResults) > 0 {
return modernResults, nilView on GitHub (pinned to beaa561337)