{"record":{"id":"ed431768238d7612","repo":"fish2018/pansou","slug":"w-ed4317","errorCode":null,"errorMessage":"创建请求失败: %w","messagePattern":"创建请求失败: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"plugin/pan666/pan666.go","lineNumber":185,"sourceCode":"\t\n\t// 按时间降序排序\n\tsort.Slice(unique, func(i, j int) bool {\n\t\treturn unique[i].Datetime.After(unique[j].Datetime)\n\t})\n\t\n\treturn unique\n}\n\n// fetchPage 获取指定页的搜索结果\nfunc (p *Pan666AsyncPlugin) fetchPage(client *http.Client, keyword string, offset int) ([]model.SearchResult, bool, error) {\n\t// 构建API URL\n\tapiURL := fmt.Sprintf(\"%s?filter[q]=%s&include=mostRelevantPost&page[offset]=%d&page[limit]=%d\",\n\t\tBaseURL, url.QueryEscape(keyword), offset, PageSize)\n\t\n\t// 创建请求\n\treq, err := http.NewRequest(\"GET\", apiURL, nil)\n\tif err != nil {\n\t\treturn nil, false, fmt.Errorf(\"创建请求失败: %w\", err)\n\t}\n\t\n\t// 设置请求头\n\treq.Header.Set(\"User-Agent\", getRandomUA())\n\treq.Header.Set(\"X-Forwarded-For\", generateRandomIP())\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(\"Sec-Fetch-Dest\", \"empty\")\n\treq.Header.Set(\"Sec-Fetch-Mode\", \"cors\")\n\treq.Header.Set(\"Sec-Fetch-Site\", \"same-origin\")\n\t\n\tvar resp *http.Response\n\tvar responseBody []byte\n\t\n\t// 重试逻辑\n\tfor i := 0; i <= p.retries; i++ {\n\t\t// 发送请求","sourceCodeStart":167,"sourceCodeEnd":203,"githubUrl":"https://github.com/fish2018/pansou/blob/beaa56133755a548ebc51b090b3816e2ae044aa6/plugin/pan666/pan666.go#L167-L203","documentation":"pan666's fetchPage fails when http.NewRequest(\"GET\", apiURL, nil) returns an error while building the search URL (BaseURL + filter[q]/include/page parameters). This only happens with a malformed URL (bad BaseURL, unescaped control characters in the query) — keyword itself is escaped with url.QueryEscape, so the cause is almost always configuration-level.","triggerScenarios":"fetchPage constructs apiURL from BaseURL and calls http.NewRequest; err is non-nil when BaseURL is empty/invalid or contains characters Go's URL parser rejects (spaces, invalid scheme, control chars).","commonSituations":"BaseURL constant changed to a value with a typo or missing scheme; BaseURL loaded from config containing trailing whitespace/newline; keyword containing characters that survive to break the URL after a refactor removed QueryEscape.","solutions":["Print the constructed apiURL and validate it parses (url.Parse) before creating the request","Check the BaseURL value has scheme https:// and no stray whitespace","Keep url.QueryEscape(keyword) applied to all user-supplied query components","Use url.Values.Encode() to build the query string instead of manual fmt.Sprintf"],"exampleFix":"// before\napiURL := fmt.Sprintf(\"%s?filter[q]=%s&include=mostRelevantPost&page[offset]=%d&page[limit]=%d\",\n    BaseURL, url.QueryEscape(keyword), offset, PageSize)\nreq, err := http.NewRequest(\"GET\", apiURL, nil)\n// after\nq := url.Values{}\nq.Set(\"filter[q]\", keyword)\nq.Set(\"include\", \"mostRelevantPost\")\nq.Set(\"page[offset]\", fmt.Sprint(offset))\nq.Set(\"page[limit]\", fmt.Sprint(PageSize))\nreq, err := http.NewRequest(\"GET\", BaseURL+\"?\"+q.Encode(), nil)","handlingStrategy":"validation","validationCode":"func validateBaseURL(raw string) error {\n    u, err := url.Parse(strings.TrimSpace(raw))\n    if err != nil { return err }\n    if u.Scheme != \"https\" || u.Host == \"\" {\n        return fmt.Errorf(\"BaseURL must be absolute https URL, got %q\", raw)\n    }\n    return nil\n}","typeGuard":null,"tryCatchPattern":"if err != nil {\n    return fmt.Errorf(\"build request: %w (url was %q)\", err, apiURL)\n}","preventionTips":["Validate BaseURL at startup with url.Parse","Build query strings with url.Values.Encode(), never raw Sprintf","Trim config-derived URLs of whitespace","Always QueryEscape user-supplied keyword values"],"tags":["http","url","request-construction","plugin"],"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"}