fish2018/pansou · error
读取响应失败
Error message
读取响应失败: %w
What it means
After the buildId HTTP response completes, io.Copy of the body into a buffer failed. Like the non-200 path, this error is only returned when there is no cached buildId to fall back on; otherwise the stale cached buildId is used silently.
Solutions
- Retry the request; transient read errors often succeed on a second attempt.
- Check network stability/proxy configuration between the host and the upstream site.
- Increase timeout margins if deadline-exceeded is the wrapped cause.
- Once a buildId is cached successfully, this path degrades to the cached value instead of erroring.
Defensive patterns
Strategy: retry
Try / catch
if err != nil && strings.Contains(err.Error(), "读取响应失败") {
// transient body read failure: retry once after short delay
time.Sleep(2 * time.Second)
results, err = plugin.Search(ctx, kw)
} Prevention
- Ensure stable network connectivity to the upstream host
- Avoid aggressively small client timeouts that can cut off body reads
- Retry transient failures — the cached buildId path usually masks these after first success
When it happens
Trigger: Calling getBuildId when reading the response body fails — typically connection reset mid-transfer, context/deadline exceeded while streaming the body, or the server closing the connection early — with an empty buildIdCache.
Common situations: Flaky network or proxy, upstream server aborting large/HTML responses, aggressive timeouts cutting off body reads.
Understand the failure class
Background: 'Something went wrong' / 'Request failed (500)' / 'HTTP error! status: 404' — what failed HTTP requests actually mean and how to find the real cause — this error's family across 28 libraries.
Related errors
AI-assisted analysis of fish2018/pansou@beaa561337 (2026-09-07).
Data as JSON: /api/errors/8310ba9d81b0994d.
Report an issue: GitHub.
Appendix: source
Thrown at plugin/pansearch/pansearch.go:434
if resp.StatusCode != 200 {
// 如果状态码不是200,但有旧的缓存,使用旧的缓存(优雅降级)
if buildIdCache != "" {
fmt.Printf("获取buildId时服务器返回非200状态码: %d,使用旧的buildId\n", resp.StatusCode)
return buildIdCache, nil
}
return "", fmt.Errorf("获取buildId时服务器返回非200状态码: %d", resp.StatusCode)
}
// 使用更高效的方式读取响应体
var bodyBuilder strings.Builder
_, err = io.Copy(&bodyBuilder, resp.Body)
if err != nil {
// 如果读取响应失败,但有旧的缓存,使用旧的缓存(优雅降级)
if buildIdCache != "" {
// fmt.Printf("读取响应失败,使用旧的buildId: %v\n", err)
return buildIdCache, nil
}
return "", fmt.Errorf("读取响应失败: %w", err)
}
body := bodyBuilder.String()
// 使用提取函数获取 buildId
buildId := extractBuildId(body)
// 如果提取失败,但有旧的缓存,使用旧的缓存(优雅降级)
if buildId == "" {
if buildIdCache != "" {
// fmt.Println("未找到buildId,使用旧的buildId")
return buildIdCache, nil
}
return "", fmt.Errorf("未找到buildId")
}
// 更新缓存
buildIdCache = buildId
buildIdCacheTime = time.Now()View on GitHub (pinned to beaa561337)