fish2018/pansou · error
[ ] 搜索返回状态码
Error message
[%s] 搜索返回状态码: %d
What it means
searchImpl returns "[%s] 搜索返回状态码" when the search page responds with a status other than 200. The plugin scrapes HTML with goquery and only handles a 200 body, so any other status is reported with its numeric code.
Solutions
- Log the status code; treat 403/429 as blocking and add cookies, referer, or realistic headers via setCommonHeaders.
- Back off and retry later for 429/5xx; reduce search request frequency.
- If 404, verify the search URL format against the live site and update searchImpl.
- Capture the response body on non-200 to identify WAF challenge pages.
Example fix
// before
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("[%s] 搜索返回状态码: %d", p.Name(), resp.StatusCode)
}
// after
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("[%s] 搜索返回状态码: %d (blocked=%v)",
p.Name(), resp.StatusCode, resp.StatusCode == 403 || resp.StatusCode == 429)
} Defensive patterns
Strategy: try-catch
Try / catch
results, err := plugin.Search(ctx, keyword)
if err != nil && strings.Contains(err.Error(), "搜索返回状态码") {
var sc int
fmt.Sscanf(err.Error(), "搜索返回状态码: %d", &sc)
if sc == 429 || sc == 403 {
// back off significantly before the next attempt
}
return nil, err
} Prevention
- Throttle search requests to avoid 429 rate limits.
- Send realistic headers (User-Agent, Referer, cookies) to pass WAF checks.
- Alert on recurring non-200 statuses — usually a site-side change, not a caller bug.
When it happens
Trigger: The search GET completes but resp.StatusCode != http.StatusOK: 404 for a moved search route, 403/429 from WAF or rate limiting, or 5xx server errors.
Common situations: Site added Cloudflare/anti-bot protection returning 403, aggressive search requests trigger 429, the WordPress-style ?s= search route changed, or the origin returns 502/504 under load.
Related errors
AI-assisted analysis of fish2018/pansou@beaa561337 (2026-09-07).
Data as JSON: /api/errors/78f4d89082001a13.
Report an issue: GitHub.
Appendix: source
Thrown at plugin/daishudj/daishudj.go:142
searchURL := fmt.Sprintf("https://www.daishuduanju.com/?s=%s", url.QueryEscape(keyword))
ctx, cancel := context.WithTimeout(context.Background(), searchTimeout)
defer cancel()
req, err := http.NewRequestWithContext(ctx, http.MethodGet, searchURL, nil)
if err != nil {
return nil, fmt.Errorf("[%s] 创建搜索请求失败: %w", p.Name(), err)
}
setCommonHeaders(req, "https://www.daishuduanju.com/")
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 != http.StatusOK {
return nil, fmt.Errorf("[%s] 搜索返回状态码: %d", p.Name(), resp.StatusCode)
}
doc, err := goquery.NewDocumentFromReader(resp.Body)
if err != nil {
return nil, fmt.Errorf("[%s] 解析搜索页面失败: %w", p.Name(), err)
}
var (
results []model.SearchResult
wg sync.WaitGroup
mu sync.Mutex
sem = make(chan struct{}, maxConcurrency)
)
doc.Find(".item-jx.item-blog").Each(func(_ int, item *goquery.Selection) {
titleSel := item.Find(".subtitle h5 a")
title := strings.TrimSpace(titleSel.Text())
detailURL, ok := titleSel.Attr("href")View on GitHub (pinned to beaa561337)