fish2018/pansou · error
[ ] 搜索页面返回状态码
Error message
[%s] 搜索页面返回状态码: %d
What it means
searchImpl requires the search page response to have status 200. Any other status — 403/503 from Cloudflare or anti-bot protection, 404 for a moved path, 429 rate limit, 5xx outage — raises this error including the plugin name and status code. The HTTP exchange itself succeeded; the server rejected or failed the request.
Solutions
- Capture and log a body snippet on non-200 to tell anti-bot pages from genuine errors.
- Update baseURL to the current working domain for the site.
- Throttle search requests and add randomized delays to avoid 429/403 rate limiting.
- Maintain cookies/session from the initial page load so challenge pages are passed.
- Retry 5xx responses with backoff; treat 403 as a signal to rotate headers or use a resolver service.
Example fix
// before
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("[%s] 搜索页面返回状态码: %d", p.Name(), resp.StatusCode)
}
// after: include a body hint for diagnosis
if resp.StatusCode != http.StatusOK {
snippet, _ := io.ReadAll(io.LimitReader(resp.Body, 256))
return nil, fmt.Errorf("[%s] 搜索页面返回状态码: %d, body=%q", p.Name(), resp.StatusCode, string(snippet))
} Defensive patterns
Strategy: fallback
Validate before calling
resp, err := http.Get(p.baseURL + "/")
if err != nil {
return err
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return fmt.Errorf("ting77 homepage returned %d — domain likely moved or blocked", resp.StatusCode)
} Type guard
func isBlockedStatus(code int) bool {
return code == 403 || code == 429 || code == 503
} Try / catch
results, err := plugin.Search(keyword)
if err != nil && strings.Contains(err.Error(), "搜索页面返回状态码") {
if strings.Contains(err.Error(), ": 403") || strings.Contains(err.Error(), ": 503") {
results, err = searchViaResolver(keyword) // challenge page: alternate route
} else {
results, err = retryWithBackoff(2, func() ([]model.Item, error) {
return plugin.Search(keyword)
})
}
} Prevention
- Monitor the site's homepage status to detect domain moves early.
- Throttle and jitter search requests to avoid rate-limit statuses.
- Persist cookies from an initial page visit to pass anti-bot challenges.
- Log a body snippet on non-200 to distinguish Cloudflare pages from real errors.
When it happens
Trigger: client.Do in searchImpl returns a response with StatusCode != http.StatusOK: bot-challenge pages on the ting77 domain, expired/moved search path, too-frequent searches, or server-side errors.
Common situations: Anti-bot (Cloudflare) interstitials when scraping without cookies; site moved to a new domain leaving the old one returning 404; hammering search triggers 429; transient 502/503 during site maintenance.
Related errors
AI-assisted analysis of fish2018/pansou@beaa561337 (2026-09-07).
Data as JSON: /api/errors/08a716eacd48f849.
Report an issue: GitHub.
Appendix: source
Thrown at plugin/ting77/ting77.go:86
if keyword == "" {
return nil, nil
}
ctx, cancel := context.WithTimeout(context.Background(), requestTimeout)
defer cancel()
searchURL := p.baseURL + "/search?q=" + url.QueryEscape(keyword)
req, err := http.NewRequestWithContext(ctx, http.MethodGet, searchURL, nil)
if err != nil {
return nil, fmt.Errorf("[%s] 创建搜索请求失败: %w", p.Name(), err)
}
setRequestHeaders(req, p.baseURL+"/", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8")
resp, err := client.Do(req)
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(io.LimitReader(resp.Body, maxResponseBytes))
if err != nil {
return nil, fmt.Errorf("[%s] 解析搜索页面失败: %w", p.Name(), err)
}
entries := parseSearchEntries(doc)
if len(entries) == 0 {
return nil, nil
}
results, resolveErr := p.resolveEntries(ctx, client, entries)
if len(results) == 0 && resolveErr != nil {
return nil, fmt.Errorf("[%s] 获取网盘链接失败: %w", p.Name(), resolveErr)
}
return plugin.FilterResultsByKeyword(results, keyword), nil
}
type searchEntry struct {View on GitHub (pinned to beaa561337)