fish2018/pansou · error

[ ] 读取响应失败

Error message

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

What it means

After a successful HTTP response, searchImpl reads the entire body with io.ReadAll. If reading fails (connection reset mid-response, context timeout during body transfer, truncated response), it wraps the error as '读取响应失败' (failed to read response).

Solutions

  1. Retry the request (doRequestWithRetry may already have succeeded but the body read is outside it — move body reading inside the retry)
  2. Increase the context timeout so the body read is not cut off
  3. Disable keep-alive or set DisableKeepAlives to avoid stale reused connections
  4. Check whether a proxy or LB is truncating responses

Example fix

// before
resp, err := p.doRequestWithRetry(req, client)
if err != nil { return nil, ... }
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil { return nil, fmt.Errorf("[%s] 读取响应失败: %w", p.Name(), err) }
// after
body, err := p.readBodyWithRetry(req, client) // body read inside retry loop
if err != nil {
    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 retrySearch(query) // transient truncation — retry
    }
    return nil, err
}

Prevention

When it happens

Trigger: The server closes the connection before the body completes; the request context times out while streaming the body; a proxy drops the connection; extremely large/aborted responses.

Common situations: Unstable network to an overseas mirror; server-side idle timeouts cutting long responses; rate limiting that closes connections; keep-alive connections reused after the server timed them out.

Understand the failure class

Background: "failed to read file", EACCES, ENOENT and "could not read <path>" errors: when a program can't read a file from disk — this error's family across 49 libraries.

Related errors


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

Appendix: source

Thrown at plugin/wanou/wanou.go:149

	// 设置请求头
	req.Header.Set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36")
	req.Header.Set("Accept", "application/json, text/plain, */*")
	req.Header.Set("Accept-Language", "zh-CN,zh;q=0.9,en;q=0.8")
	req.Header.Set("Connection", "keep-alive")
	req.Header.Set("Referer", "https://woog.nxog.eu.org/")
	req.Header.Set("Cache-Control", "no-cache")
	
	// 发送请求
	resp, err := p.doRequestWithRetry(req, client)
	if err != nil {
		return nil, fmt.Errorf("[%s] 搜索请求失败: %w", p.Name(), err)
	}
	defer resp.Body.Close()
	
	// 解析JSON响应
	body, err := io.ReadAll(resp.Body)
	if err != nil {
		return nil, fmt.Errorf("[%s] 读取响应失败: %w", p.Name(), err)
	}
	
	var apiResponse WanouAPIResponse
	if err := json.Unmarshal(body, &apiResponse); err != nil {
		return nil, fmt.Errorf("[%s] 解析JSON响应失败: %w", p.Name(), err)
	}
	
	// 检查API响应状态
	if apiResponse.Code != 1 {
		return nil, fmt.Errorf("[%s] API返回错误: %s", p.Name(), apiResponse.Msg)
	}
	
	// 解析搜索结果
	var results []model.SearchResult
	for _, item := range apiResponse.List {
		if result := p.parseAPIItem(item); result.Title != "" {
			results = append(results, result)
		}

View on GitHub (pinned to beaa561337)