fish2018/pansou · error
[ ] 网盘第 页请求失败
Error message
[%s] %s网盘第%d页请求失败: %w
What it means
fetchSearchPage sends the search request through p.doRequestWithRetry and wraps any transport-level failure with this message including plugin name, pan type, and page. The wrapped %w error carries the underlying cause — DNS failure, connection refused/reset, TLS error, or exhausting the retry attempts.
Solutions
- Read the wrapped error (%w cause) to distinguish timeout vs connection-refused vs TLS.
- Check basic connectivity: curl https://haisou.cc/ from the same host.
- Increase the 30s context timeout if responses are merely slow.
- If the site blocks you, change egress IP or add delays/reduce concurrency.
Example fix
// before
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
// after
ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second)
var lastErr error
for attempt := 0; attempt < 3; attempt++ {
if _, err = fetchPage(ctx, pageNo); err == nil { break }
lastErr = err
time.Sleep(time.Duration(attempt+1) * 2 * time.Second)
} Defensive patterns
Strategy: retry
Validate before calling
// verify egress before issuing the search
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
req, _ := http.NewRequestWithContext(ctx, http.MethodHead, "https://haisou.cc/", nil)
if _, err := http.DefaultClient.Do(req); err != nil {
return fmt.Errorf("network unavailable: %w", err)
} Type guard
func isNetworkError(err error) bool {
var ne net.Error
return errors.As(err, &ne) || errors.Is(err, context.DeadlineExceeded)
} Try / catch
items, err := fetchSearchPage(panType, keyword, pageNo)
if isNetworkError(err) {
time.Sleep(time.Duration(attempt) * 2 * time.Second) // exponential backoff
items, err = fetchSearchPage(panType, keyword, pageNo)
} Prevention
- Use generous context timeouts relative to expected response times.
- Keep the built-in retry mechanism enabled with backoff.
- Monitor DNS/proxy health on the deployment host.
- Reduce request frequency if the site starts resetting connections.
When it happens
Trigger: Calling fetchSearchPage when the HTTP round-trip fails even after retries: haisou.cc unreachable, connection reset/blocked, TLS handshake failure, context deadline exceeded (30s timeout), or the client's proxy is down.
Common situations: Deployment host without internet/egress; site blocking the IP at TCP/TLS level; haisou.cc DNS records changed; transient network outage during retries; timeout on slow responses.
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/2a9e3551c624548f.
Report an issue: GitHub.
Appendix: source
Thrown at plugin/haisou/haisou.go:341
defer cancel()
// 创建请求对象
req, err := http.NewRequestWithContext(ctx, "GET", searchURL, nil)
if err != nil {
return nil, fmt.Errorf("[%s] %s网盘第%d页创建请求失败: %w", p.Name(), panType, pageNo, err)
}
// 设置请求头
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://haisou.cc/")
// 发送HTTP请求(带重试机制)
resp, err := p.doRequestWithRetry(req, client)
if err != nil {
return nil, fmt.Errorf("[%s] %s网盘第%d页请求失败: %w", p.Name(), panType, pageNo, err)
}
defer resp.Body.Close()
// 检查状态码
if resp.StatusCode != 200 {
return nil, fmt.Errorf("[%s] %s网盘第%d页返回状态码: %d", p.Name(), panType, pageNo, resp.StatusCode)
}
// 读取响应体
body, err := io.ReadAll(resp.Body)
if err != nil {
return nil, fmt.Errorf("[%s] %s网盘第%d页读取响应失败: %w", p.Name(), panType, pageNo, err)
}
// 解析响应
var apiResp SearchAPIResponse
if err := json.Unmarshal(body, &apiResp); err != nil {
return nil, fmt.Errorf("[%s] %s网盘第%d页JSON解析失败: %w", p.Name(), panType, pageNo, err)View on GitHub (pinned to beaa561337)