{"record":{"id":"299ff72b2c64ba6c","repo":"fish2018/pansou","slug":"s-w-299ff7","errorCode":null,"errorMessage":"[%s] 搜索请求失败: %w","messagePattern":"\\[(.+?)\\] 搜索请求失败: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"plugin/qingying/qingying.go","lineNumber":131,"sourceCode":"\t\n\treturn filtered\n}\n\nfunc (p *QingYingPlugin) fetchSearchResults(searchURL string, client *http.Client) ([]searchItem, error) {\n\tdebugPrintf(\"🌐 请求搜索页面: %s\\n\", searchURL)\n\tctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)\n\tdefer cancel()\n\t\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\tp.setHeaders(req, baseURL)\n\t\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\tdebugPrintf(\"📡 HTTP状态码: %d\\n\", resp.StatusCode)\n\t\n\tif resp.StatusCode != 200 {\n\t\treturn nil, fmt.Errorf(\"[%s] 请求返回状态码: %d\", p.Name(), resp.StatusCode)\n\t}\n\t\n\tdoc, err := goquery.NewDocumentFromReader(resp.Body)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"[%s] HTML解析失败: %w\", p.Name(), err)\n\t}\n\t\n\tvar items []searchItem\n\tdoc.Find(\"div.module-search-item\").Each(func(i int, s *goquery.Selection) {\n\t\tlink := s.Find(\".video-info .video-info-header h3 a\")\n\t\thref, exists := link.Attr(\"href\")","sourceCodeStart":113,"sourceCodeEnd":149,"githubUrl":"https://github.com/fish2018/pansou/blob/beaa56133755a548ebc51b090b3816e2ae044aa6/plugin/qingying/qingying.go#L113-L149","documentation":"fetchSearchResults wraps an error from doRequestWithRetry for the search request: every retry attempt failed at the transport level (DNS, connect, TLS, or timeout). The plugin name and wrapped cause are included.","triggerScenarios":"p.doRequestWithRetry(req, client) returns err after all retries for the search URL — site down, connection refused, TLS handshake failure, or the 30-second context deadline exceeded on each attempt.","commonSituations":"The aggregation site is offline or changed domain; local DNS cannot resolve the host; firewall/proxy blocks the connection; heavy search load makes each attempt exceed the 30s timeout.","solutions":["Unwrap the error to identify the root cause (timeout, refused, TLS) with errors.As.","Confirm reachability with curl using the same URL and headers; fix proxy/DNS accordingly.","Raise the context timeout (30s) or the retry count if the site is merely slow.","Check whether the site moved domains and update baseURL in the plugin config."],"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    return nil, fmt.Errorf(\"[%s] 搜索请求失败(请检查网络或站点可达性): %w\", p.Name(), err)\n}","handlingStrategy":"retry","validationCode":"u, _ := url.Parse(baseURL)\nconn, err := net.DialTimeout(\"tcp\", net.JoinHostPort(u.Hostname(), \"443\"), 5*time.Second)\nif err != nil {\n    log.Println(\"qingying site unreachable, skip\")\n    return\n}\nconn.Close()","typeGuard":"func isTimeoutErr(err error) bool {\n    var nerr net.Error\n    return errors.As(err, &nerr) && nerr.Timeout()\n}","tryCatchPattern":"results, err := plugin.Search(keyword)\nif err != nil {\n    if strings.Contains(err.Error(), \"搜索请求失败\") && isTimeoutErr(err) {\n        time.Sleep(time.Minute) // backoff, then retry\n        return plugin.Search(keyword)\n    }\n    return nil, err\n}","preventionTips":["Set generous timeouts for slow aggregator sites.","Verify DNS/proxy can reach the site before scheduled searches.","Add exponential backoff between retry rounds.","Unwrap *url.Error to log the real network cause."],"tags":["network","retry-exhausted","http-client","timeout"],"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"}