{"record":{"id":"ad66930ece31e0c5","repo":"fish2018/pansou","slug":"s-w-ad6693","errorCode":null,"errorMessage":"[%s] 创建网页搜索请求失败: %w","messagePattern":"\\[(.+?)\\] 创建网页搜索请求失败: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"plugin/feikuai/feikuai.go","lineNumber":177,"sourceCode":"\t\t\t\tresults = append(results, result)\n\t\t\t}\n\t\t}\n\t}\n\n\t// 使用关键词过滤结果\n\treturn plugin.FilterResultsByKeyword(results, keyword), nil\n}\n\n// searchWebFallback parses the current server-rendered external search page.\n// Feikuai's legacy JSON endpoint now responds with 403, while this page still\n// exposes both disk links and magnets in stable HTML markup.\nfunc (p *FeikuaiPlugin) searchWeb(client *http.Client, keyword string, apiErr error) ([]model.SearchResult, error) {\n\tctx, cancel := context.WithTimeout(context.Background(), DefaultTimeout)\n\tdefer cancel()\n\tsearchURL := SearchWebURL + \"?wd=\" + url.QueryEscape(keyword) + \"&ext=1\"\n\treq, err := http.NewRequestWithContext(ctx, http.MethodGet, searchURL, nil)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"[%s] 创建网页搜索请求失败: %w\", p.Name(), err)\n\t}\n\treq.Header.Set(\"User-Agent\", \"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 Chrome/136.0.0.0 Safari/537.36\")\n\treq.Header.Set(\"Accept\", \"text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\")\n\treq.Header.Set(\"Accept-Language\", \"zh-CN,zh;q=0.9,en;q=0.8\")\n\treq.Header.Set(\"Referer\", \"https://feikuai.in/\")\n\tresp, err := client.Do(req)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"[%s] API 失败且网页搜索请求失败: %v (API: %v)\", p.Name(), err, apiErr)\n\t}\n\tdefer resp.Body.Close()\n\tif resp.StatusCode != http.StatusOK {\n\t\treturn nil, fmt.Errorf(\"[%s] API 失败且网页搜索返回状态码 %d (API: %v)\", p.Name(), resp.StatusCode, apiErr)\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","sourceCodeStart":159,"sourceCodeEnd":195,"githubUrl":"https://github.com/fish2018/pansou/blob/beaa56133755a548ebc51b090b3816e2ae044aa6/plugin/feikuai/feikuai.go#L159-L195","documentation":"searchWeb is the HTML scraping fallback used when the JSON API path fails; it builds a second request to SearchWebURL and wraps any construction error in this message. As with the API path, this fires before any bytes hit the network.","triggerScenarios":"http.NewRequestWithContext(ctx, http.MethodGet, SearchWebURL+\"?wd=\"+url.QueryEscape(keyword)+\"&ext=1\", nil) fails — malformed URL composition or illegal characters after concatenation.","commonSituations":"Stale or mistyped SearchWebURL constant, keyword containing characters that break the URL even after QueryEscape (e.g. embedded control chars), domain rotation mistakes.","solutions":["Validate the composed searchURL with url.Parse before creating the request","Check the SearchWebURL constant and query string composition","Confirm url.QueryEscape is applied to all user-supplied parts"],"exampleFix":"// before\nsearchURL := SearchWebURL + \"?wd=\" + url.QueryEscape(keyword) + \"&ext=1\"\nreq, err := http.NewRequestWithContext(ctx, http.MethodGet, searchURL, nil)\n// after\nu, uerr := url.Parse(SearchWebURL)\nif uerr != nil {\n    return nil, fmt.Errorf(\"invalid SearchWebURL %q: %w\", SearchWebURL, uerr)\n}\nq := u.Query(); q.Set(\"wd\", keyword); q.Set(\"ext\", \"1\"); u.RawQuery = q.Encode()\nreq, err := http.NewRequestWithContext(ctx, http.MethodGet, u.String(), nil)","handlingStrategy":"validation","validationCode":"u, err := url.Parse(SearchWebURL)\nif err != nil || u.Host == \"\" {\n    return nil, fmt.Errorf(\"invalid SearchWebURL %q: %w\", SearchWebURL, err)\n}","typeGuard":null,"tryCatchPattern":"results, err := plugin.Search(keyword)\nif err != nil && strings.Contains(err.Error(), \"创建网页搜索请求失败\") {\n    return nil, fmt.Errorf(\"feikuai web fallback misconfigured: %w\", err)\n}","preventionTips":["Compose fallback URLs with url.Values, never raw string concatenation","Keep API and web URL constants in one config validated at startup","Re-verify both endpoints whenever the upstream site rotates domains","Escape all keyword input via url.QueryEscape"],"tags":["http","url","scraping"],"backgroundTag":"invalid-url","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"}