{"record":{"id":"295fbbe98b844746","repo":"fish2018/pansou","slug":"w-295fbb","errorCode":null,"errorMessage":"创建搜索请求失败: %w","messagePattern":"创建搜索请求失败: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"plugin/panwiki/panwiki.go","lineNumber":234,"sourceCode":"\t}\n\t\n\t// 如果不是第一页，修改URL中的page参数\n\tif page > 1 {\n\t\tif strings.Contains(searchURL, \"searchid=\") {\n\t\t\t// 提取searchid并构建分页URL\n\t\t\tre := regexp.MustCompile(`searchid=(\\d+)`)\n\t\t\tmatches := re.FindStringSubmatch(searchURL)\n\t\t\tif len(matches) > 1 {\n\t\t\t\tsearchid := matches[1]\n\t\t\t\tsearchURL = fmt.Sprintf(\"%s/search.php?mod=forum&searchid=%s&orderby=lastpost&ascdesc=desc&searchsubmit=yes&page=%d\", p.currentBaseURL, searchid, page)\n\t\t\t}\n\t\t}\n\t}\n\t\n\t// Step 2: 请求实际的搜索结果页面\n\treq2, err := http.NewRequest(\"GET\", searchURL, nil)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"创建搜索请求失败: %w\", err)\n\t}\n\t\n\tp.setRequestHeaders(req2)\n\t\n\tresp2, err := client.Do(req2)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"搜索请求失败: %w\", err)\n\t}\n\tdefer resp2.Body.Close()\n\t\n\tif resp2.StatusCode != http.StatusOK {\n\t\treturn nil, fmt.Errorf(\"搜索请求返回状态码: %d\", resp2.StatusCode)\n\t}\n\t\n\t// 解析搜索结果\n\tdoc, err := goquery.NewDocumentFromReader(resp2.Body)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"解析HTML失败: %w\", err)","sourceCodeStart":216,"sourceCodeEnd":252,"githubUrl":"https://github.com/fish2018/pansou/blob/beaa56133755a548ebc51b090b3816e2ae044aa6/plugin/panwiki/panwiki.go#L216-L252","documentation":"After resolving the redirect target, searchPage builds a second http.NewRequest for the actual results page. If the searchURL assembled from the Location header is malformed (bad scheme, invalid characters, empty host after string concatenation), http.NewRequest fails and the error is wrapped as \"创建搜索请求失败\".","triggerScenarios":"http.NewRequest(\"GET\", searchURL, nil) returns a url.Parse error — typically because the Location header contained a malformed relative path that p.currentBaseURL + \"/\" concatenation turned into an invalid URL, or the header contained spaces/illegal characters.","commonSituations":"Upstream returns an unexpected relative Location (e.g. containing characters needing escaping, or protocol-relative \"//host/...\" mishandled by naive concatenation); base URL misconfigured with wrong scheme; site change alters Location format.","solutions":["Log the failing searchURL value to inspect the malformed URL.","Use net/url to parse the Location and ResolveReference against the base URL instead of string concatenation.","url.QueryEscape / path escaping for any user-derived parts embedded in the URL.","Validate that p.currentBaseURL includes the correct scheme (https://)."],"exampleFix":"// before\nsearchURL = p.currentBaseURL + \"/\" + strings.TrimPrefix(location, \"/\")\n// after\nbase, _ := url.Parse(p.currentBaseURL)\nref, err := url.Parse(location)\nif err != nil {\n    return nil, fmt.Errorf(\"解析重定向URL失败: %w\", err)\n}\nsearchURL = base.ResolveReference(ref).String()","handlingStrategy":"validation","validationCode":"// Go: validate the URL before constructing the request\nu, err := url.Parse(searchURL)\nif err != nil || u.Scheme == \"\" || u.Host == \"\" {\n    return nil, fmt.Errorf(\"invalid searchURL: %q\", searchURL)\n}","typeGuard":null,"tryCatchPattern":"results, err := plugin.Search(keyword, page)\nif err != nil {\n    var ue *url.Error\n    if errors.As(err, &ue) {\n        log.Printf(\"bad URL %q: %v\", ue.URL, ue.Err)\n    }\n    return err\n}","preventionTips":["Use url.ResolveReference instead of string concatenation for relative Locations.","Always log the offending URL string on request-construction failure.","Validate base URL has scheme and host at config load time."],"tags":["http","url","go","scraping"],"backgroundTag":"invalid-url-format","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"}