fish2018/pansou · error
请求失败,状态码: ,且读取响应体错误
Error message
请求失败,状态码: %d,且读取响应体错误: %v
What it means
When the homepage responds with a non-200 status code, the function reads the response body to include the server's error details. If even reading that body fails (connection reset mid-read, context canceled, body already consumed), it returns this combined message: the numeric status code plus the body-read error. It signals both a failed request outcome and a degraded ability to diagnose it.
Solutions
- Retry with backoff — connection resets on non-200 responses are usually transient or rate-limit related.
- Check for rate limiting (429) or blocking (403) and slow down / rotate the User-Agent or IP.
- Increase the HTTP client timeout so the body read can complete.
- Add http.NoBody / status-only fallback: log the status code even when the body cannot be read, so diagnosis doesn't depend on the body.
- Verify the User-Agent/header set is not triggering immediate connection drops from the WAF.
Example fix
// before
return nil, fmt.Errorf("请求失败,状态码: %d,且读取响应体错误: %v", resp.StatusCode, err)
// after
if resp.StatusCode == http.StatusTooManyRequests {
return nil, fmt.Errorf("请求被限流(429),请降低频率: 读取响应体错误: %v", err)
}
return nil, fmt.Errorf("请求失败,状态码: %d,且读取响应体错误: %w", resp.StatusCode, err) Defensive patterns
Strategy: retry
Try / catch
_, err := discoverActionIDs(ctx)
if err != nil {
var httpErr *HTTPStatusError
if errors.As(err, &httpErr) && isRetryable(httpErr.StatusCode) {
return retryWithBackoff(ctx)
}
return err
} Prevention
- Throttle calls to discoverActionIDs to avoid 429-driven connection drops.
- Send complete browser-like headers to reduce WAF resets.
- Set client timeout longer than worst-case response time.
- Log the status code independently of the body so failures stay diagnosable.
When it happens
Trigger: Server returned e.g. 403/429/502 from findPotentialActionIDs' homepage request AND io.ReadAll(resp.Body) errored — typically because the server closed the connection immediately after sending headers, or the request context deadline expired during the read.
Common situations: Anti-bot/WAF (e.g. Cloudflare) returns 403 and immediately resets the connection; rate limiter closes the socket; server sends Content-Length but truncates the body; client timeout set shorter than server response time.
Understand the failure class
Background: "API error: {status}" and "HTTP 401/403/404/429/5xx" errors: non-2xx HTTP responses explained — this error's family across 27 libraries.
Related errors
AI-assisted analysis of fish2018/pansou@beaa561337 (2026-09-07).
Data as JSON: /api/errors/664b94d59ec0fc62.
Report an issue: GitHub.
Appendix: source
Thrown at plugin/panyq/panyq.go:671
// 只保留指定的请求头
// req.Header.Set("sec-ch-ua", `"Not)A;Brand";v="8", "Chromium";v="138", "Google Chrome";v="138"`)
req.Header.Set("User-Agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36")
// 发送请求
resp, err := client.Do(req)
if err != nil {
return nil, fmt.Errorf("请求网站首页失败: %w", err)
}
defer resp.Body.Close()
// 检查状态码
if resp.StatusCode != http.StatusOK {
// 读取响应体以获取服务器返回的具体错误信息
bodyBytes, err := io.ReadAll(resp.Body)
if err != nil {
// 如果连响应体都读取失败,则返回状态码错误并附上读取错误
return nil, fmt.Errorf("请求失败,状态码: %d,且读取响应体错误: %v", resp.StatusCode, err)
}
// 将更详细的状态信息 (如 "404 Not Found") 和响应体内容一起作为错误返回
return nil, fmt.Errorf("请求失败,状态: %s, 详情: %s", resp.Status, string(bodyBytes))
}
body, err := io.ReadAll(resp.Body)
if err != nil {
return nil, fmt.Errorf("读取响应失败: %w", err)
}
// 提取JS文件路径
jsRegex := regexp.MustCompile(`<script src="(/_next/static/[^"]+\.js)"`)
matches := jsRegex.FindAllStringSubmatch(string(body), -1)
if len(matches) == 0 {
return nil, fmt.Errorf("未找到JS文件")
}
View on GitHub (pinned to beaa561337)