fish2018/pansou · error
[susu] 按钮列表请求返回状态码
Error message
[susu] 按钮列表请求返回状态码: %d
What it means
getLinks throws this when the button-list API responds with a non-200 status code after a successful transport round-trip. The body is not read or parsed; the status code is reported verbatim so callers can diagnose whether it's auth (403), rate limiting (429), server error (5xx), or a wrong-endpoint 404.
Solutions
- Read the status code from the message; 403/503 usually means bot protection — refresh setAPIHeaders/cookies.
- If 429, add delays between getLinks calls or implement backoff.
- If 404/405, verify ButtonListURL against the current site API.
- If 5xx, retry later or extend doRequestWithRetry to retry on 5xx.
- Capture a sample response body (before discarding) to confirm WAF/challenge pages.
Example fix
null
Defensive patterns
Strategy: retry
Try / catch
links, err := p.getLinks(postID)
if err != nil {
if strings.Contains(err.Error(), "按钮列表请求返回状态码: 429") {
time.Sleep(backoff)
// retry once
}
} Prevention
- Keep setAPIHeaders/referer current to avoid 403 challenges
- Throttle getLinks calls per postID
- Retry on 5xx/429 only; surface 4xx to the user
- Alert on persistent non-200s indicating API drift
When it happens
Trigger: The POST to ButtonListURL returns resp.StatusCode != http.StatusOK — e.g. WAF challenge (403), rate limit (429), server maintenance (503), or 404 after an API endpoint change.
Common situations: Anti-bot defenses flagging the API request (headers/cookies stale); hammering the API and getting 429; the site changing its API and returning 404/405; Cloudflare 5xx during incidents.
Related errors
AI-assisted analysis of fish2018/pansou@beaa561337 (2026-09-07).
Data as JSON: /api/errors/453ea0621a57ad26.
Report an issue: GitHub.
Appendix: source
Thrown at plugin/susu/susu.go:359
"post_id": {postID},
"guest": {""},
}
ctx, cancel := context.WithTimeout(context.Background(), 20*time.Second)
defer cancel()
req, err := http.NewRequestWithContext(ctx, http.MethodPost, ButtonListURL, strings.NewReader(form.Encode()))
if err != nil {
return nil, fmt.Errorf("[susu] 创建按钮列表请求失败: %w", err)
}
setAPIHeaders(req, fmt.Sprintf("%s/%s.html", BaseURL, postID))
resp, err := p.doRequestWithRetry(client, req, MaxRetries)
if err != nil {
return nil, fmt.Errorf("[susu] 获取按钮列表失败: %w", err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("[susu] 按钮列表请求返回状态码: %d", resp.StatusCode)
}
respBody, err := io.ReadAll(io.LimitReader(resp.Body, 2<<20))
if err != nil {
return nil, fmt.Errorf("[susu] 读取按钮列表失败: %w", err)
}
var groups []downloadGroup
if err := json.Unmarshal(respBody, &groups); err != nil {
return nil, fmt.Errorf("[susu] 解析按钮列表失败: %w", err)
}
totalButtons := 0
for _, group := range groups {
totalButtons += len(group.Button)
}
if totalButtons == 0 {
return nil, fmt.Errorf("[susu] 帖子 %s 没有可用下载按钮", postID)View on GitHub (pinned to beaa561337)