fish2018/pansou · error
[ ] 第 页搜索请求失败
Error message
[%s] 第%d页搜索请求失败: %w
What it means
fetchPage executes the search request through doRequestWithRetry, which retries non-200 responses and network errors. If all attempts fail, the last error is wrapped with the plugin name and page number. This is the terminal network-failure error for a page fetch.
Solutions
- Inspect the wrapped cause (%w) to distinguish timeout/connection vs status-code failures.
- Add backoff/jitter between retries and cap retry count to avoid triggering rate limits.
- Rotate User-Agent / add delays if the site blocks scripted requests.
- Verify network connectivity and proxy settings in the deployment environment.
Defensive patterns
Strategy: retry
Validate before calling
if err := connectivityProbe(searchHost); err != nil {
return fmt.Errorf("network unreachable before search: %w", err)
} Type guard
func isRetryableNetErr(err error) bool {
var ne net.Error
return errors.As(err, &ne) || errors.Is(err, syscall.ECONNRESET) || errors.Is(err, syscall.ECONNREFUSED)
} Try / catch
pr, err := fetchPage(page, keyword)
if err != nil {
var ne net.Error
if errors.As(err, &ne) && ne.Timeout() {
time.Sleep(2 * time.Second)
pr, err = fetchPage(page, keyword)
}
if err != nil { return nil, err }
} Prevention
- Use exponential backoff with jitter between retries to avoid tripping rate limits.
- Distinguish timeouts from status failures by inspecting the wrapped cause.
- Set explicit client Timeout and cap the retry count.
When it happens
Trigger: Every attempt in doRequestWithRetry failed: timeouts, connection refused/reset, TLS errors, or the site kept returning non-OK status codes (see error 819 for the non-200 cause).
Common situations: Site is down or rate-limiting your IP; aggressive retry loop triggered anti-bot blocking; proxy misconfigured; DNS failure in the deployment environment; page number beyond what the site supports.
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/3d8486df804199be.
Report an issue: GitHub.
Appendix: source
Thrown at plugin/xiaoyu/xiaoyu.go:158
}
return plugin.FilterResultsByKeyword(results, keyword), nil
}
func (p *XiaoyuPlugin) fetchPage(client *http.Client, keyword string, page int) (pageResult, error) {
requestURL := fmt.Sprintf(searchURL, page, url.PathEscape(keyword))
ctx, cancel := context.WithTimeout(context.Background(), requestTimeout)
defer cancel()
req, err := http.NewRequestWithContext(ctx, http.MethodGet, requestURL, nil)
if err != nil {
return pageResult{}, fmt.Errorf("[%s] 创建第%d页请求失败: %w", p.Name(), page, err)
}
setRequestHeaders(req)
resp, err := doRequestWithRetry(client, req)
if err != nil {
return pageResult{}, fmt.Errorf("[%s] 第%d页搜索请求失败: %w", p.Name(), page, err)
}
defer resp.Body.Close()
doc, err := goquery.NewDocumentFromReader(io.LimitReader(resp.Body, maxResponseSize))
if err != nil {
return pageResult{}, fmt.Errorf("[%s] 第%d页解析失败: %w", p.Name(), page, err)
}
return parsePage(doc), nil
}
func setRequestHeaders(req *http.Request) {
req.Header.Set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.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("Referer", baseURL+"/")
}View on GitHub (pinned to beaa561337)