{"record":{"id":"f2e01ff9b0097da9","repo":"fish2018/pansou","slug":"s-w-f2e01f","errorCode":null,"errorMessage":"[%s] 创建请求失败: %w","messagePattern":"\\[(.+?)\\] 创建请求失败: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"plugin/ahhhhfs/ahhhhfs.go","lineNumber":166,"sourceCode":"\t\tfmt.Printf(\"[%s] 搜索耗时: %v\\n\", p.Name(), time.Since(start))\n\t}()\n\n\t// 使用优化的客户端\n\tif p.optimizedClient != nil {\n\t\tclient = p.optimizedClient\n\t}\n\n\t// 1. 构建搜索URL\n\tsearchURL := fmt.Sprintf(\"https://www.ahhhhfs.com/?cat=&s=%s\", url.QueryEscape(keyword))\n\t\n\t// 2. 创建带超时的上下文\n\tctx, cancel := context.WithTimeout(context.Background(), DefaultTimeout)\n\tdefer cancel()\n\t\n\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/120.0.0.0 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://www.ahhhhfs.com/\")\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","sourceCodeStart":148,"sourceCodeEnd":184,"githubUrl":"https://github.com/fish2018/pansou/blob/beaa56133755a548ebc51b090b3816e2ae044aa6/plugin/ahhhhfs/ahhhhfs.go#L148-L184","documentation":"The ahhhhfs plugin's searchImpl wraps any error from http.NewRequestWithContext when building the GET search request to www.ahhhhfs.com as '[%s] 创建请求失败'. net/http validates the method, URL, and body at construction; with hardcoded 'GET' and a fixed searchURL, this only fires if the search URL is malformed (nil context, bad scheme, invalid characters in the URL).","triggerScenarios":"http.NewRequestWithContext(ctx, \"GET\", searchURL, nil) returns err — an unparseable searchURL (e.g. a keyword not properly URL-escaped producing spaces/control chars, or a broken baseURL constant) or a nil/invalid context.","commonSituations":"A developer edited the searchURL construction and forgot url.QueryEscape on the keyword, leaving raw spaces or CJK characters in the URL; a configuration-driven domain replacement injected an invalid host; manual refactor introduced a bad scheme.","solutions":["Inspect the wrapped %w error — net/http states which part of the request is invalid.","Ensure the search keyword is passed through url.QueryEscape when interpolating into searchURL.","Run url.Parse(searchURL) before building the request and fail fast with a clear message on malformed URLs.","Pin down where searchURL comes from (constant vs config) and validate it at plugin startup."],"exampleFix":"// before\nsearchURL := \"https://www.ahhhhfs.com/?s=\" + keyword\nreq, err := http.NewRequestWithContext(ctx, \"GET\", searchURL, nil)\nif err != nil {\n    return nil, fmt.Errorf(\"[%s] 创建请求失败: %w\", p.Name(), err)\n}\n// after\nsearchURL := \"https://www.ahhhhfs.com/?s=\" + url.QueryEscape(keyword)\nreq, err := http.NewRequestWithContext(ctx, \"GET\", searchURL, nil)\nif err != nil {\n    return nil, fmt.Errorf(\"[%s] 创建请求失败: %w\", p.Name(), err)\n}","handlingStrategy":"validation","validationCode":"searchURL := \"https://www.ahhhhfs.com/?s=\" + url.QueryEscape(keyword)\nif u, err := url.Parse(searchURL); err != nil || u.Host == \"\" {\n    return fmt.Errorf(\"非法搜索URL: %q\", searchURL)\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always url.QueryEscape user-supplied keywords before URL interpolation.","Validate constructed URLs with url.Parse before http.NewRequestWithContext.","Keep the context non-nil and derived from context.WithTimeout."],"tags":["go","http","url"],"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"}