{"record":{"id":"8a13921f14c52491","repo":"fish2018/pansou","slug":"s-w-8a1392","errorCode":null,"errorMessage":"[%s] 搜索请求失败: %w","messagePattern":"\\[(.+?)\\] 搜索请求失败: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"plugin/duoduo/duoduo.go","lineNumber":179,"sourceCode":"\t// 3. 创建请求\n\treq, err := http.NewRequestWithContext(ctx, \"GET\", searchURL, nil)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"[%s] 创建请求失败: %w\", p.Name(), err)\n\t}\n\t\n\t// 4. 设置完整的请求头（避免反爬虫）\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\", \"text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8\")\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(\"Upgrade-Insecure-Requests\", \"1\")\n\treq.Header.Set(\"Cache-Control\", \"max-age=0\")\n\treq.Header.Set(\"Referer\", \"https://tv.yydsys.top/\")\n\t\n\t// 5. 发送请求（带重试机制）\n\tresp, err := p.doRequestWithRetry(req, client)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"[%s] 搜索请求失败: %w\", p.Name(), err)\n\t}\n\tdefer resp.Body.Close()\n\t\n\tif resp.StatusCode != 200 {\n\t\treturn nil, fmt.Errorf(\"[%s] 搜索请求返回状态码: %d\", p.Name(), resp.StatusCode)\n\t}\n\t\n\t// 6. 解析搜索结果页面\n\tdoc, err := goquery.NewDocumentFromReader(resp.Body)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"[%s] 解析搜索页面失败: %w\", p.Name(), err)\n\t}\n\t\n\t// 7. 提取搜索结果\n\tvar results []model.SearchResult\n\t\n\tdoc.Find(\".module-search-item\").Each(func(i int, s *goquery.Selection) {\n\t\tresult := p.parseSearchItem(s, keyword)","sourceCodeStart":161,"sourceCodeEnd":197,"githubUrl":"https://github.com/fish2018/pansou/blob/beaa56133755a548ebc51b090b3816e2ae044aa6/plugin/duoduo/duoduo.go#L161-L197","documentation":"searchImpl wraps any error returned by doRequestWithRetry — the HTTP GET to the duoduo search page failed after all configured retry attempts. This covers transport-level failures: DNS resolution, TCP connect, TLS handshake, context deadline exceeded, and proxy errors. The underlying net.Error / context error is preserved via %w.","triggerScenarios":"doRequestWithRetry(req, client) exhausts its retry loop because every attempt returns a non-nil error (server unreachable, DNS failure, TLS errors, or the DefaultTimeout context expired).","commonSituations":"Target site tv.yydsys.top is down or blocked; developer is behind a firewall/proxy; DNS cannot resolve the domain; network is slow enough that DefaultTimeout expires on every attempt; running from a region where the site is geo-blocked.","solutions":["Test connectivity to the site directly (curl -v the search URL) to confirm it is reachable.","Increase DefaultTimeout in the plugin or the retry count in doRequestWithRetry if the site is slow.","Check for required proxy settings; if the site needs one, configure the http.Client transport with a proxy.","Handle the wrapped error with errors.As for *net.OpError / context.DeadlineExceeded and surface a clear message or fall back to another plugin."],"exampleFix":"// before\nresp, err := p.doRequestWithRetry(req, client)\nif err != nil {\n    return nil, fmt.Errorf(\"[%s] 搜索请求失败: %w\", p.Name(), err)\n}\n// after\nresp, err := p.doRequestWithRetry(req, client)\nif err != nil {\n    if errors.Is(err, context.DeadlineExceeded) {\n        return nil, fmt.Errorf(\"[%s] 搜索超时，站点不可达或超时过短: %w\", p.Name(), err)\n    }\n    return nil, fmt.Errorf(\"[%s] 搜索请求失败: %w\", p.Name(), err)\n}","handlingStrategy":"retry","validationCode":"func canReach(urlStr string) bool {\n    ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)\n    defer cancel()\n    req, err := http.NewRequestWithContext(ctx, http.MethodHead, urlStr, nil)\n    if err != nil { return false }\n    resp, err := http.DefaultClient.Do(req)\n    if err != nil { return false }\n    resp.Body.Close()\n    return true\n}","typeGuard":null,"tryCatchPattern":"if err != nil {\n    var netErr net.Error\n    switch {\n    case errors.Is(err, context.DeadlineExceeded):\n        // treat as timeout: lengthen timeout or skip source\n    case errors.As(err, &netErr):\n        // transient network issue: retry with backoff\n    default:\n        // unexpected: log and fall back to another plugin\n    }\n}","preventionTips":["Configure sane timeout and retry counts for slow upstreams.","Check site reachability before enabling the plugin.","Support proxy configuration for geo-blocked sources.","Fall back to alternate search sources on persistent failure."],"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"}