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

  1. Retry the request; transient read errors often succeed on a second attempt.
  2. Check network stability/proxy configuration between the host and the upstream site.
  3. Increase timeout margins if deadline-exceeded is the wrapped cause.
  4. 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

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)