fish2018/pansou · error
[ ] 搜索返回状态码
Error message
[%s] 搜索返回状态码: %d
What it means
searchImpl rejects any alupan search response whose HTTP status code is not 200. The site responded, but with an error/redirect status (e.g. 403 anti-bot block, 429 rate limit, 5xx server error, or 3xx redirect not followed), so the HTML parsing step would be meaningless.
Solutions
- Log resp.Status and the response body snippet to see what the site actually returned (403 pages often contain a WAF challenge).
- Compare headers sent by setCommonHeaders with a real browser request; update User-Agent/Referer/Accept to avoid bot detection.
- Honor 429: add backoff (retryBaseDelay already exists) and reduce request concurrency (maxConcurrency = 12 may be too aggressive).
- Handle 3xx explicitly by checking client.CheckRedirect if redirects are being stopped.
- Treat 5xx as transient — surface it to the retry loop instead of failing immediately.
Example fix
// before
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("[%s] 搜索返回状态码: %d", p.Name(), resp.StatusCode)
}
// after
if resp.StatusCode == http.StatusTooManyRequests {
time.Sleep(retryBaseDelay * 2)
// retry or return a typed rate-limit error
}
if resp.StatusCode != http.StatusOK {
body, _ := io.ReadAll(io.LimitReader(resp.Body, 512))
return nil, fmt.Errorf("[%s] 搜索返回状态码: %d, body: %s", p.Name(), resp.StatusCode, body)
} Defensive patterns
Strategy: fallback
Validate before calling
// After receiving a response, inspect status before parsing
if resp.StatusCode != http.StatusOK {
body, _ := io.ReadAll(io.LimitReader(resp.Body, 256))
log.Printf("aliupan status=%d body=%q", resp.StatusCode, body)
} Try / catch
// Go: treat non-200 as a typed condition and fall back
results, err := plugin.Search(keyword, ext)
if err != nil && strings.Contains(err.Error(), "搜索返回状态码") {
// extract code, apply backoff for 429/5xx, then continue with other plugins
time.Sleep(retryBaseDelay)
} Prevention
- Match real browser headers (User-Agent, Accept, Referer) to avoid 403 WAF blocks.
- Throttle concurrency and honor 429 Retry-After to avoid rate limiting.
- Retry 5xx as transient; fail fast on 4xx after logging the body.
- Alert on status-code changes — they usually mean the site changed its protection or structure.
When it happens
Trigger: doRequestWithRetry returns a response whose StatusCode != http.StatusOK — typically 403/429 (bot protection, rate limiting), 404 (site structure changed), 500/502/503 (server-side problems), or 301/302 when redirects are disabled.
Common situations: The site enabled Cloudflare or WAF bot detection and returns 403 to the plugin's headers; the host is rate-limited after heavy scraping (429); the site is temporarily down (5xx); a URL or redirect policy change in the http.Client stops redirects from being followed.
Related errors
AI-assisted analysis of fish2018/pansou@beaa561337 (2026-09-07).
Data as JSON: /api/errors/dd92d1def528f3ad.
Report an issue: GitHub.
Appendix: source
Thrown at plugin/alupan/alupan.go:138
searchURL := fmt.Sprintf("https://www.aliupan.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.aliupan.com/")
resp, err := p.doRequestWithRetry(req, client, searchMaxRetries)
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("article.excerpt").Each(func(_ int, item *goquery.Selection) {
titleSel := item.Find("header h2 a")
title := strings.TrimSpace(titleSel.Text())
detailURL, ok := titleSel.Attr("href")View on GitHub (pinned to beaa561337)