fish2018/pansou · error

[ ] 读取响应失败

Error message

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

What it means

ClmaoPlugin.searchPage fails while reading the HTTP response body with io.ReadAll. Since the status already passed the 200 check, this is almost always a mid-stream network failure (connection reset, unexpected EOF) or the request context expiring while the body is still streaming.

Solutions

  1. Check the wrapped error: context.DeadlineExceeded means the timeout hit during body read — increase TimeoutSeconds.
  2. Retry the request; mid-stream resets are often transient and re-entering searchPage reuses doRequestWithRetry.
  3. Use io.LimitReader to bound body size and avoid pathological huge reads.
  4. Ensure resp.Body is fully drained/closed promptly so keep-alive connections aren't broken.

Example fix

// before
body, err := io.ReadAll(resp.Body)
if err != nil {
    return nil, fmt.Errorf("[%s] 读取响应失败: %w", p.Name(), err)
}
// after
body, err := io.ReadAll(io.LimitReader(resp.Body, 10<<20))
if err != nil {
    if errors.Is(err, context.DeadlineExceeded) {
        return nil, fmt.Errorf("[%s] 读取响应超时,尝试增大 TimeoutSeconds: %w", p.Name(), err)
    }
    return nil, fmt.Errorf("[%s] 读取响应失败: %w", p.Name(), err)
}
Defensive patterns

Strategy: retry

Try / catch

body, err := io.ReadAll(resp.Body)
if err != nil {
    if errors.Is(err, context.DeadlineExceeded) || errors.Is(err, io.ErrUnexpectedEOF) {
        return retryOnce(req) // transient mid-stream failure
    }
    return nil, fmt.Errorf("[%s] 读取响应失败: %w", p.Name(), err)
}

Prevention

When it happens

Trigger: After a 200 response, body, err := io.ReadAll(resp.Body) errors — the connection dropped mid-transfer, the server truncated the response, or ctx (TimeoutSeconds) expired during body read — producing "[clmao] 读取响应失败: %w".

Common situations: Slow/large responses exceeding the TimeoutSeconds budget (deadline hits while reading); flaky networks or proxies closing connections; anti-bot middleboxes resetting the connection after headers were sent.

Related errors


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

Appendix: source

Thrown at plugin/clmao/clmao.go:200

	// 设置请求头
	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)
	}

	decodedHTML := decodeModernPayload(string(body))
	if decodedHTML != string(body) {
		if modernResults := p.parseModernSearchResults(client, decodedHTML); len(modernResults) > 0 {
			return modernResults, nil
		}
	}

	// 兼容旧模板
	doc, err := goquery.NewDocumentFromReader(strings.NewReader(decodedHTML))
	if err != nil {
		return nil, fmt.Errorf("[%s] HTML解析失败: %w", p.Name(), err)
	}

	// 提取搜索结果
	return p.extractSearchResults(doc), nil
}

View on GitHub (pinned to beaa561337)