fish2018/pansou · error

读取验证响应失败

Error message

读取验证响应失败: %w

What it means

The verification response body could not be read: io.ReadAll(resp.Body) failed after a successful HTTP exchange, so solveVerification wraps the error as 读取验证响应失败. This indicates the connection dropped mid-body or the server sent a malformed/truncated stream.

Solutions

  1. Retry the whole verification flow (getDetailInfo already retries alternate candidate URLs)
  2. Increase the request timeout so the read isn't cut off by ctx deadline
  3. Verify no proxy/middlebox truncates responses; test with curl
  4. Check the wrapped error — 'unexpected EOF' vs 'context deadline exceeded' points to different fixes
Defensive patterns

Strategy: retry

Try / catch

info, err := plugin.GetDetailInfo(ctx, url)
if err != nil && strings.Contains(err.Error(), "读取验证响应失败") {
    time.Sleep(time.Second)
    info, err = plugin.GetDetailInfo(ctx, url) // transient read failures usually succeed on retry
}

Prevention

When it happens

Trigger: io.ReadAll(resp.Body) errors in solveVerification — server closed the connection prematurely, chunked encoding interrupted, or a proxy reset the stream during the challenge response download.

Common situations: Unstable network or flaky CDN; aggressive server-side connection limits killing keep-alive connections; middleboxes/proxies truncating responses; response is huge and the timeout/context expires mid-read.

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/875971902b1f317b. Report an issue: GitHub.

Appendix: source

Thrown at plugin/qiwei/qiwei.go:400

	query.Set("value", encodedValue)
	verifyURL += "?" + query.Encode()

	ctx, cancel := context.WithTimeout(context.Background(), detailTimeout)
	defer cancel()
	req, err := http.NewRequestWithContext(ctx, http.MethodGet, verifyURL, nil)
	if err != nil {
		return fmt.Errorf("创建验证请求失败: %w", err)
	}
	p.setHeaders(req, pageURL)
	req.Header.Set("X-Requested-With", "XMLHttpRequest")
	resp, err := p.doRequestWithRetry(req, client)
	if err != nil {
		return fmt.Errorf("提交验证失败: %w", err)
	}
	defer resp.Body.Close()
	responseBody, err := io.ReadAll(resp.Body)
	if err != nil {
		return fmt.Errorf("读取验证响应失败: %w", err)
	}
	if isVerifyPage(string(responseBody)) {
		return fmt.Errorf("站点未接受验证参数")
	}
	return nil
}

func md5StringToHex(value string) string {
	var builder strings.Builder
	for _, r := range value {
		builder.WriteString(fmt.Sprintf("%d", r+1))
	}
	sum := md5.Sum([]byte(builder.String()))
	return hex.EncodeToString(sum[:])
}

func (p *QiweiPlugin) parseDetail(detailURL, body, fallbackTitle, fallbackPic string) (detailInfo, error) {
	doc, err := goquery.NewDocumentFromReader(strings.NewReader(body))

View on GitHub (pinned to beaa561337)