fish2018/pansou · error
[ ] 读取响应体失败
Error message
[%s] 读取响应体失败: %w
What it means
dyyj.executeSearchHTML could not read the response body: io.ReadAll(resp.Body) returned an error. This means the connection broke mid-body (unexpected EOF, connection reset) or a body-limiting reader failed.
Solutions
- Simply retry — transient mid-body resets usually succeed on a second attempt
- Wrap the body in a size-limited reader (io.LimitReader) and read with a longer deadline
- Check proxy stability if a proxy is in the path
- Increase client/transport timeouts so slow bodies finish reading
Example fix
// before
bodyBytes, err := io.ReadAll(resp.Body)
// after
bodyBytes, err := io.ReadAll(io.LimitReader(resp.Body, 10<<20))
if err != nil && resp.StatusCode == http.StatusOK {
// retry the request once on truncated body
} Defensive patterns
Strategy: retry
Validate before calling
// before calling: ensure client has sane timeouts
client := &http.Client{ Timeout: 30 * time.Second } Try / catch
bodyBytes, err := io.ReadAll(io.LimitReader(resp.Body, maxBodySize))
if err != nil {
if errors.Is(err, io.ErrUnexpectedEOF) || errors.Is(err, syscall.ECONNRESET) {
return p.retryOnce(req) // transient truncation: retry
}
return nil, fmt.Errorf("read body failed: %w", err)
} Prevention
- Cap body reads with io.LimitReader to bound memory and read time
- Use clients with explicit timeouts on slow sites
- Avoid long-lived flaky proxies; test proxy stability
- Retry once on unexpected EOF before surfacing the error
When it happens
Trigger: io.ReadAll(resp.Body) failed on a 200 response — server closed the connection mid-transfer, read timeout hit during body streaming, or a custom body-limited reader errored.
Common situations: Unstable network or flaky proxy dropping long responses; server-side timeout closing slow connections; body size cap in a wrapping transport exceeded.
Related errors
AI-assisted analysis of fish2018/pansou@beaa561337 (2026-09-07).
Data as JSON: /api/errors/70674aab3693bff0.
Report an issue: GitHub.
Appendix: source
Thrown at plugin/dyyj/dyyj.go:279
if p.debugMode {
log.Printf("[DYYJ] 搜索请求响应状态码: %d", resp.StatusCode)
}
if resp.StatusCode != 200 {
if p.debugMode {
log.Printf("[DYYJ] 搜索请求HTTP状态错误: %d", resp.StatusCode)
}
return nil, fmt.Errorf("[%s] 搜索请求HTTP状态错误: %d", p.Name(), resp.StatusCode)
}
// 读取响应体用于调试
bodyBytes, err := io.ReadAll(resp.Body)
if err != nil {
if p.debugMode {
log.Printf("[DYYJ] 读取响应体失败: %v", err)
}
return nil, fmt.Errorf("[%s] 读取响应体失败: %w", p.Name(), err)
}
bodyString := string(bodyBytes)
if p.debugMode {
log.Printf("[DYYJ] 响应体大小: %d 字节", len(bodyString))
// 保存完整HTML到文件用于分析
filename := fmt.Sprintf("./dyyj_search_%s_%d.html", url.QueryEscape(keyword), time.Now().Unix())
if err := os.WriteFile(filename, bodyBytes, 0644); err == nil {
log.Printf("[DYYJ] 完整HTML已保存到: %s", filename)
} else {
log.Printf("[DYYJ] 保存HTML文件失败: %v", err)
}
// 输出HTML的前2000个字符用于调试
previewLen := 2000
if len(bodyString) < previewLen {
previewLen = len(bodyString)View on GitHub (pinned to beaa561337)