fish2018/pansou · error

[ ] 读取响应失败

Error message

[%s] 读取响应失败: %w

What it means

searchPage wraps the error from io.ReadAll(resp.Body): the response body could not be fully read from the network connection. Because defer resp.Body.Close() runs right after, this typically means the connection dropped mid-transfer (unexpected EOF, connection reset by peer) or the compressed/encoded stream was corrupt.

Solutions

  1. Check the wrapped error (unexpected EOF vs context deadline vs connection reset)
  2. Retry the search — transient truncation often succeeds on a second attempt
  3. Increase MaxRetries in doRequestWithRetry to cover mid-body drops
  4. Increase TimeoutSeconds if the deadline is being hit on large pages
  5. Ensure no misconfigured proxy is intercepting and truncating traffic
Defensive patterns

Strategy: retry

Try / catch

results, err := p.Search(keyword, ext)
if err != nil && strings.Contains(err.Error(), "读取响应失败") {
    // transient body read failure: retry with backoff
    time.Sleep(time.Second)
    results, err = p.Search(keyword, ext)
}

Prevention

When it happens

Trigger: io.ReadAll(resp.Body) fails after a 200 response: server closed the connection mid-body, TLS truncation, proxy interference, or an interrupted read hitting the 30s context deadline.

Common situations: Flaky upstream site or CDN dropping large HTML pages; overloaded server truncating responses; NAT/firewall killing long-lived connections; unstable network on the host running pansou.

Related errors


AI-assisted analysis of fish2018/pansou@beaa561337 (2026-09-07). Data as JSON: /api/errors/5351e7935ba2fb61. Report an issue: GitHub.

Appendix: source

Thrown at plugin/wuji/wuji.go:203

	// 设置请求头
	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)
	}
	
	// 解析HTML
	doc, err := goquery.NewDocumentFromReader(strings.NewReader(string(body)))
	if err != nil {
		return nil, fmt.Errorf("[%s] HTML解析失败: %w", p.Name(), err)
	}
	
	// 提取搜索结果
	return p.extractSearchResults(doc), nil
}

// extractSearchResults 提取搜索结果
func (p *WujiPlugin) extractSearchResults(doc *goquery.Document) []model.SearchResult {
	var results []model.SearchResult
	
	// 查找所有搜索结果
	doc.Find("table.file-list tbody tr").Each(func(i int, s *goquery.Selection) {

View on GitHub (pinned to beaa561337)