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

  1. Simply retry — transient mid-body resets usually succeed on a second attempt
  2. Wrap the body in a size-limited reader (io.LimitReader) and read with a longer deadline
  3. Check proxy stability if a proxy is in the path
  4. 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

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)