fish2018/pansou · error

请求失败,状态码: ,且读取响应体错误

Error message

请求失败,状态码: %d,且读取响应体错误: %v

What it means

When the homepage responds with a non-200 status code, the function reads the response body to include the server's error details. If even reading that body fails (connection reset mid-read, context canceled, body already consumed), it returns this combined message: the numeric status code plus the body-read error. It signals both a failed request outcome and a degraded ability to diagnose it.

Solutions

  1. Retry with backoff — connection resets on non-200 responses are usually transient or rate-limit related.
  2. Check for rate limiting (429) or blocking (403) and slow down / rotate the User-Agent or IP.
  3. Increase the HTTP client timeout so the body read can complete.
  4. Add http.NoBody / status-only fallback: log the status code even when the body cannot be read, so diagnosis doesn't depend on the body.
  5. Verify the User-Agent/header set is not triggering immediate connection drops from the WAF.

Example fix

// before
return nil, fmt.Errorf("请求失败,状态码: %d,且读取响应体错误: %v", resp.StatusCode, err)
// after
if resp.StatusCode == http.StatusTooManyRequests {
    return nil, fmt.Errorf("请求被限流(429),请降低频率: 读取响应体错误: %v", err)
}
return nil, fmt.Errorf("请求失败,状态码: %d,且读取响应体错误: %w", resp.StatusCode, err)
Defensive patterns

Strategy: retry

Try / catch

_, err := discoverActionIDs(ctx)
if err != nil {
    var httpErr *HTTPStatusError
    if errors.As(err, &httpErr) && isRetryable(httpErr.StatusCode) {
        return retryWithBackoff(ctx)
    }
    return err
}

Prevention

When it happens

Trigger: Server returned e.g. 403/429/502 from findPotentialActionIDs' homepage request AND io.ReadAll(resp.Body) errored — typically because the server closed the connection immediately after sending headers, or the request context deadline expired during the read.

Common situations: Anti-bot/WAF (e.g. Cloudflare) returns 403 and immediately resets the connection; rate limiter closes the socket; server sends Content-Length but truncates the body; client timeout set shorter than server response time.

Understand the failure class

Background: "API error: {status}" and "HTTP 401/403/404/429/5xx" errors: non-2xx HTTP responses explained — this error's family across 27 libraries.

Related errors


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

Appendix: source

Thrown at plugin/panyq/panyq.go:671

	
	// 只保留指定的请求头
	// req.Header.Set("sec-ch-ua", `"Not)A;Brand";v="8", "Chromium";v="138", "Google Chrome";v="138"`)
	req.Header.Set("User-Agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36")
	
	// 发送请求
	resp, err := client.Do(req)
	if err != nil {
		return nil, fmt.Errorf("请求网站首页失败: %w", err)
	}
	defer resp.Body.Close()
	
	// 检查状态码
	if resp.StatusCode != http.StatusOK {
		// 读取响应体以获取服务器返回的具体错误信息
		bodyBytes, err := io.ReadAll(resp.Body)
		if err != nil {
			// 如果连响应体都读取失败,则返回状态码错误并附上读取错误
			return nil, fmt.Errorf("请求失败,状态码: %d,且读取响应体错误: %v", resp.StatusCode, err)
		}
		// 将更详细的状态信息 (如 "404 Not Found") 和响应体内容一起作为错误返回
		return nil, fmt.Errorf("请求失败,状态: %s, 详情: %s", resp.Status, string(bodyBytes))
	}

	body, err := io.ReadAll(resp.Body)
	if err != nil {
		return nil, fmt.Errorf("读取响应失败: %w", err)
	}
	
	// 提取JS文件路径
	jsRegex := regexp.MustCompile(`<script src="(/_next/static/[^"]+\.js)"`)
	matches := jsRegex.FindAllStringSubmatch(string(body), -1)
	
	if len(matches) == 0 {
		return nil, fmt.Errorf("未找到JS文件")
	}
	

View on GitHub (pinned to beaa561337)