fish2018/pansou · error
[ ] 请求返回状态码
Error message
[%s] 请求返回状态码: %d
What it means
ClmaoPlugin.searchPage received an HTTP response whose status code is not 200 and turns it into an error that includes the actual code. The retry helper doRequestWithRetry only retries transport errors, so a non-200 (403 Forbidden, 429 Too Many Requests, 503, 404) reaches this check on the first attempt and fails immediately — these statuses are not retried.
Solutions
- Log the status code and a response-body snippet to identify whether it's 403 (blocked), 429 (rate limited), or 404/5xx.
- For 403: refresh/update cookies and User-Agent in setRequestHeaders to match a real browser.
- For 429: back off and slow down request frequency; respect Retry-After header.
- For 404: check whether the site changed its search endpoint and update searchURL.
- Optionally extend doRequestWithRetry to retry on 429/5xx with backoff.
Example fix
// before
if resp.StatusCode != 200 {
return nil, fmt.Errorf("[%s] 请求返回状态码: %d", p.Name(), resp.StatusCode)
}
// after
if resp.StatusCode == http.StatusTooManyRequests {
if ra := resp.Header.Get("Retry-After"); ra != "" {
if secs, e := strconv.Atoi(ra); e == nil { time.Sleep(time.Duration(secs) * time.Second) }
}
return nil, fmt.Errorf("[%s] rate limited (429)", p.Name())
}
if resp.StatusCode != 200 {
return nil, fmt.Errorf("[%s] 请求返回状态码: %d", p.Name(), resp.StatusCode)
} Defensive patterns
Strategy: fallback
Validate before calling
// pre-flight status probe
func statusOK(client *http.Client, url string) (bool, int) {
resp, err := client.Get(url)
if err != nil { return false, 0 }
defer resp.Body.Close()
return resp.StatusCode == http.StatusOK, resp.StatusCode
} Try / catch
results, err := p.searchPage(client, keyword, page)
if err != nil {
if strings.Contains(err.Error(), "429") {
time.Sleep(rateLimitBackoff) // retry later
} else if strings.Contains(err.Error(), "403") {
refreshSessionCookies()
}
return nil, err
} Prevention
- Rotate/refresh User-Agent and cookies to avoid 403 blocks.
- Rate-limit your search volume to avoid 429s.
- Alert on recurring non-200 codes — they usually mean site changes or blocks.
- Consider adding 429/5xx handling into the plugin's retry loop.
When it happens
Trigger: p.doRequestWithRetry returns a valid *http.Response whose resp.StatusCode != 200 — e.g. 403 from missing/expired cookies, 429 after too-frequent searches, or 503 during maintenance — and searchPage returns "[clmao] 请求返回状态码: %d".
Common situations: Anti-bot protection flagging the default User-Agent; running many searches in a short window and hitting rate limits; the site changed its URL structure so the old search path now 404s; the site is temporarily under maintenance (503).
Related errors
AI-assisted analysis of fish2018/pansou@beaa561337 (2026-09-07).
Data as JSON: /api/errors/a1083c50e86f86f7.
Report an issue: GitHub.
Appendix: source
Thrown at plugin/clmao/clmao.go:194
// 创建请求
req, err := http.NewRequestWithContext(ctx, "GET", searchURL, nil)
if err != nil {
return nil, fmt.Errorf("[%s] 创建请求失败: %w", p.Name(), err)
}
// 设置请求头
p.setRequestHeaders(req)
// 发送HTTP请求
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 != 200 {
return nil, fmt.Errorf("[%s] 请求返回状态码: %d", p.Name(), resp.StatusCode)
}
// 读取响应体内容
body, err := io.ReadAll(resp.Body)
if err != nil {
return nil, fmt.Errorf("[%s] 读取响应失败: %w", p.Name(), err)
}
decodedHTML := decodeModernPayload(string(body))
if decodedHTML != string(body) {
if modernResults := p.parseModernSearchResults(client, decodedHTML); len(modernResults) > 0 {
return modernResults, nil
}
}
// 兼容旧模板
doc, err := goquery.NewDocumentFromReader(strings.NewReader(decodedHTML))
if err != nil {View on GitHub (pinned to beaa561337)