{"record":{"id":"2a9e3551c624548f","repo":"fish2018/pansou","slug":"s-s-d-w-2a9e35","errorCode":null,"errorMessage":"[%s] %s网盘第%d页请求失败: %w","messagePattern":"\\[(.+?)\\] (.+?)网盘第(.+?)页请求失败: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"plugin/haisou/haisou.go","lineNumber":341,"sourceCode":"\tdefer cancel()\n\n\t// 创建请求对象\n\treq, err := http.NewRequestWithContext(ctx, \"GET\", searchURL, nil)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"[%s] %s网盘第%d页创建请求失败: %w\", p.Name(), panType, pageNo, err)\n\t}\n\n\t// 设置请求头\n\treq.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\")\n\treq.Header.Set(\"Accept\", \"application/json, text/plain, */*\")\n\treq.Header.Set(\"Accept-Language\", \"zh-CN,zh;q=0.9,en;q=0.8\")\n\treq.Header.Set(\"Connection\", \"keep-alive\")\n\treq.Header.Set(\"Referer\", \"https://haisou.cc/\")\n\n\t// 发送HTTP请求（带重试机制）\n\tresp, err := p.doRequestWithRetry(req, client)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"[%s] %s网盘第%d页请求失败: %w\", p.Name(), panType, pageNo, err)\n\t}\n\tdefer resp.Body.Close()\n\n\t// 检查状态码\n\tif resp.StatusCode != 200 {\n\t\treturn nil, fmt.Errorf(\"[%s] %s网盘第%d页返回状态码: %d\", p.Name(), panType, pageNo, resp.StatusCode)\n\t}\n\n\t// 读取响应体\n\tbody, err := io.ReadAll(resp.Body)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"[%s] %s网盘第%d页读取响应失败: %w\", p.Name(), panType, pageNo, err)\n\t}\n\n\t// 解析响应\n\tvar apiResp SearchAPIResponse\n\tif err := json.Unmarshal(body, &apiResp); err != nil {\n\t\treturn nil, fmt.Errorf(\"[%s] %s网盘第%d页JSON解析失败: %w\", p.Name(), panType, pageNo, err)","sourceCodeStart":323,"sourceCodeEnd":359,"githubUrl":"https://github.com/fish2018/pansou/blob/beaa56133755a548ebc51b090b3816e2ae044aa6/plugin/haisou/haisou.go#L323-L359","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)\n// after\nctx, cancel := context.WithTimeout(context.Background(), 60*time.Second)\nvar lastErr error\nfor attempt := 0; attempt < 3; attempt++ {\n    if _, err = fetchPage(ctx, pageNo); err == nil { break }\n    lastErr = err\n    time.Sleep(time.Duration(attempt+1) * 2 * time.Second)\n}","handlingStrategy":"retry","validationCode":"// verify egress before issuing the search\nctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)\ndefer cancel()\nreq, _ := http.NewRequestWithContext(ctx, http.MethodHead, \"https://haisou.cc/\", nil)\nif _, err := http.DefaultClient.Do(req); err != nil {\n    return fmt.Errorf(\"network unavailable: %w\", err)\n}","typeGuard":"func isNetworkError(err error) bool {\n  var ne net.Error\n  return errors.As(err, &ne) || errors.Is(err, context.DeadlineExceeded)\n}","tryCatchPattern":"items, err := fetchSearchPage(panType, keyword, pageNo)\nif isNetworkError(err) {\n    time.Sleep(time.Duration(attempt) * 2 * time.Second) // exponential backoff\n    items, err = fetchSearchPage(panType, keyword, pageNo)\n}","preventionTips":["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."],"tags":["network","http","timeout","retry"],"backgroundTag":"http-request-failed","analyzedSha":"beaa56133755a548ebc51b090b3816e2ae044aa6","analyzedAt":"2026-09-07T00:31:18.025Z","contentChangedAt":"2026-09-07T00:31:18.025Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}