{"record":{"id":"4a30dec0d7681776","repo":"fish2018/pansou","slug":"s-w-4a30de","errorCode":null,"errorMessage":"[%s] 创建请求失败: %w","messagePattern":"\\[(.+?)\\] 创建请求失败: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"plugin/alupan/alupan.go","lineNumber":126,"sourceCode":"\t}\n\treturn &http.Client{\n\t\tTransport: transport,\n\t\tTimeout:   searchTimeout,\n\t}\n}\n\nfunc (p *AlupanPlugin) searchImpl(client *http.Client, keyword string, ext map[string]interface{}) ([]model.SearchResult, error) {\n\tif p.client != nil {\n\t\tclient = p.client\n\t}\n\n\tsearchURL := fmt.Sprintf(\"https://www.aliupan.com/?s=%s\", url.QueryEscape(keyword))\n\tctx, cancel := context.WithTimeout(context.Background(), searchTimeout)\n\tdefer cancel()\n\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\n\tsetCommonHeaders(req, \"https://www.aliupan.com/\")\n\n\tresp, err := p.doRequestWithRetry(req, client, searchMaxRetries)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"[%s] 搜索请求失败: %w\", p.Name(), err)\n\t}\n\tdefer resp.Body.Close()\n\n\tif resp.StatusCode != http.StatusOK {\n\t\treturn nil, fmt.Errorf(\"[%s] 搜索返回状态码: %d\", p.Name(), resp.StatusCode)\n\t}\n\n\tdoc, err := goquery.NewDocumentFromReader(resp.Body)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"[%s] 解析搜索页面失败: %w\", p.Name(), err)\n\t}","sourceCodeStart":108,"sourceCodeEnd":144,"githubUrl":"https://github.com/fish2018/pansou/blob/beaa56133755a548ebc51b090b3816e2ae044aa6/plugin/alupan/alupan.go#L108-L144","documentation":"searchImpl in the alupan plugin wraps errors from http.NewRequestWithContext when building the GET request to https://www.aliupan.com/?s=<keyword>. With a plain method, an absolute URL, and a nil body, NewRequestWithContext essentially only fails on malformed URL parsing, so this indicates the constructed search URL could not be parsed into a valid *http.Request.","triggerScenarios":"http.NewRequestWithContext returns an error — practically only when the formatted URL fails url.Parse (invalid characters/structure) or the context is nil. Since the URL is a fixed template with url.QueryEscape(keyword), this is rare.","commonSituations":"A code change removes the url.QueryEscape call so the raw keyword produces an invalid URL (e.g. contains spaces or control characters); the base URL string is edited into a malformed literal; a nil context is passed after refactoring.","solutions":["Check the exact keyword at runtime — log or inspect it for control/invalid URL characters.","Ensure url.QueryEscape is applied to the keyword in the Sprintf call.","Verify the base URL constant is a valid absolute URL (https://www.aliupan.com/).","Confirm the context passed to NewRequestWithContext is non-nil (it is created on the line above; refactors may have broken that)."],"exampleFix":"// before\nsearchURL := fmt.Sprintf(\"https://www.aliupan.com/?s=%s\", keyword)\n// after\nsearchURL := fmt.Sprintf(\"https://www.aliupan.com/?s=%s\", url.QueryEscape(keyword))","handlingStrategy":"validation","validationCode":"// Validate the URL before building the request\nu, err := url.Parse(fmt.Sprintf(\"https://www.aliupan.com/?s=%s\", url.QueryEscape(keyword)))\nif err != nil {\n    return nil, fmt.Errorf(\"invalid search URL: %w\", err)\n}\nif u.Scheme != \"https\" || u.Host == \"\" {\n    return nil, fmt.Errorf(\"unexpected search URL: %s\", u)\n}","typeGuard":null,"tryCatchPattern":"if req, err := http.NewRequestWithContext(ctx, http.MethodGet, searchURL, nil); err != nil {\n    return nil, fmt.Errorf(\"[%s] 创建请求失败: %w\", p.Name(), err)\n}","preventionTips":["Always url.QueryEscape user-supplied keywords before embedding them in URLs.","Keep the base URL as a validated constant checked at startup.","Never pass a nil context into NewRequestWithContext.","Add a startup self-test that builds a sample request to catch URL regressions early."],"tags":["http","url","request-construction","go"],"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"}