fish2018/pansou · error
请求返回状态码
Error message
请求返回状态码: %d
What it means
fetchSearchResults in the xdpan plugin performs an HTTP GET to the search site and requires HTTP 200. Any other status code aborts parsing and is returned as this error, so the developer sees only the numeric status instead of the response body.
Solutions
- Log resp.StatusCode and dump a snippet of resp.Body before returning to identify the blocker
- Check the cf-mitigated response header to detect Cloudflare challenges and switch to a browser-like flow
- Slow down request rate and honor Retry-After for 429
- Update/verify baseURL and search path if the site changed
- Use doRequestWithRetry which already retries transient non-200s
Example fix
// before
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("请求返回状态码: %d", resp.StatusCode)
}
// after
if resp.StatusCode != http.StatusOK {
body, _ := io.ReadAll(io.LimitReader(resp.Body, 512))
return nil, fmt.Errorf("请求返回状态码: %d, 响应: %s", resp.StatusCode, body)
} Defensive patterns
Strategy: try-catch
Validate before calling
// Go has no pre-call validation for remote status; probe first:
resp, err := client.Head(searchURL)
if err == nil && resp.StatusCode != http.StatusOK {
return fmt.Errorf("站点当前不可用: %d", resp.StatusCode)
} Try / catch
results, err := plugin.Search(ctx, kw)
if err != nil {
var statusErr *fmt.StatusError // or match on the message
if strings.Contains(err.Error(), "请求返回状态码") {
// degrade gracefully: return empty results and notify
return fallbackResults, nil
}
return err
} Prevention
- Monitor target site status and Cloudflare changes
- Throttle request rate to avoid 429
- Keep baseURL and paths up to date
- Log response body snippets on non-200
When it happens
Trigger: Any non-200 response from the search endpoint during searchImpl: 403/503 from Cloudflare or WAF, 404 after a site URL/path change, 429 rate limiting, 5xx upstream outage.
Common situations: Site migrated behind Cloudflare bot protection; too-frequent scraping triggering 429; stale baseURL pointing to a dead page; server temporarily down.
Understand the failure class
Background: "API error: {status}" and "HTTP 401/403/404/429/5xx" errors: non-2xx HTTP responses explained — this error's family across 27 libraries.
Related errors
AI-assisted analysis of fish2018/pansou@beaa561337 (2026-09-07).
Data as JSON: /api/errors/7aad262746fb61a0.
Report an issue: GitHub.
Appendix: source
Thrown at plugin/xdpan/xdpan.go:119
req, err := http.NewRequestWithContext(ctx, "GET", searchURL, nil)
if err != nil {
return nil, fmt.Errorf("创建GET请求失败: %w", err)
}
p.setRequestHeaders(req)
if DebugLog {
fmt.Printf("[xdpan] 搜索URL: %s\n", searchURL)
}
resp, err := p.doRequestWithRetry(req, client)
if err != nil {
return nil, fmt.Errorf("GET请求失败: %w", err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("请求返回状态码: %d", resp.StatusCode)
}
// 解析HTML
doc, err := goquery.NewDocumentFromReader(io.LimitReader(resp.Body, maxPageSize))
if err != nil {
return nil, fmt.Errorf("解析HTML失败: %w", err)
}
results := p.extractSearchResults(doc)
if len(results) == 0 && doc.Find("title").First().Text() == "Just a moment..." {
return nil, fmt.Errorf("站点触发 Cloudflare 浏览器验证")
}
return results, nil
}
// extractSearchResults 从搜索页面提取结果
func (p *XdpanPlugin) extractSearchResults(doc *goquery.Document) []model.SearchResult {
var results []model.SearchResultView on GitHub (pinned to beaa561337)