fish2018/pansou · error

[ ] 第 页搜索请求失败

Error message

[%s] 第%d页搜索请求失败: %w

What it means

searchPage wraps an error from the underlying HTTP client.Do for page N of the dy4k search. The preceding code classifies netErr.Timeout()/Temporary(), but regardless of type the request failed at the transport level after (possibly) retries. The wrapped cause is preserved for errors.Is/As inspection.

Solutions

  1. Read the debug output / unwrap the error to distinguish timeout vs reset vs DNS and act accordingly.
  2. Increase DefaultTimeout and add per-page throttling or a worker limit to avoid hammering the site.
  3. Configure a working proxy if the site is unreachable from the current network.
  4. Implement bounded retry with backoff for Temporary network errors before surfacing the failure.

Example fix

// before
return nil, 0, fmt.Errorf("[%s] 第%d页搜索请求失败: %w", p.Name(), page, err)
// after
var netErr net.Error
if errors.As(err, &netErr) && netErr.Timeout() {
    return nil, 0, fmt.Errorf("[%s] 第%d页请求超时(考虑增大DefaultTimeout): %w", p.Name(), page, err)
}
return nil, 0, fmt.Errorf("[%s] 第%d页搜索请求失败: %w", p.Name(), page, err)
Defensive patterns

Strategy: retry

Try / catch

var netErr net.Error
if errors.As(err, &netErr) {
    if netErr.Timeout() {
        // increase timeout or skip page
    } else if ne, ok := err.(*net.OpError); ok && isTransient(ne) {
        // retry with exponential backoff
    }
}

Prevention

When it happens

Trigger: client.Do(req) returns an error on page N: context deadline (DefaultTimeout) exceeded, connection reset/refused, DNS failure, or proxy/SOCKS5 dial failure. The surrounding debug output explicitly checks net.Error Timeout/Temporary, so timeouts are a first-class trigger.

Common situations: Target site slow or blocking by IP so requests hang past DefaultTimeout; too many parallel page requests cause connection resets; no/broken proxy configured while the site requires one; IPv6 issues causing hangs.

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

Appendix: source

Thrown at plugin/dy4k/dy4k.go:405

	}

	startTime := time.Now()
	resp, err := p.doRequestWithRetry(req, client)
	requestDuration := time.Since(startTime)

	if err != nil {
		debugPrintf("❌ [Dy4k DEBUG] HTTP请求失败 (耗时: %v): %v\n", requestDuration, err)
		debugPrintf("❌ [Dy4k DEBUG] 错误类型分析:\n")
		if netErr, ok := err.(*url.Error); ok {
			fmt.Printf("    URL错误: %v\n", netErr.Err)
			if netErr.Timeout() {
				fmt.Printf("    -> 这是超时错误\n")
			}
			if netErr.Temporary() {
				fmt.Printf("    -> 这是临时错误\n")
			}
		}
		return nil, 0, fmt.Errorf("[%s] 第%d页搜索请求失败: %w", p.Name(), page, err)
	}
	defer resp.Body.Close()

	debugPrintf("✅ [Dy4k DEBUG] HTTP请求成功 (耗时: %v)\n", requestDuration)

	// 6. 检查状态码
	debugPrintf("🔧 [Dy4k DEBUG] HTTP响应状态码: %d\n", resp.StatusCode)
	if resp.StatusCode != 200 {
		debugPrintf("❌ [Dy4k DEBUG] 状态码异常: %d\n", resp.StatusCode)
		return nil, 0, fmt.Errorf("[%s] 第%d页请求返回状态码: %d", p.Name(), page, resp.StatusCode)
	}

	// 7. 读取并打印HTML响应
	htmlBytes, err := io.ReadAll(resp.Body)
	if err != nil {
		return nil, 0, fmt.Errorf("[%s] 第%d页读取响应失败: %w", p.Name(), page, err)
	}

View on GitHub (pinned to beaa561337)