fish2018/pansou · error
[ ] 创建请求失败
Error message
[%s] 创建请求失败: %w
What it means
searchAtBase builds a GET http.Request via http.NewRequestWithContext for the mirror's search URL. If the URL is malformed (unparseable), NewRequestWithContext fails and the error is wrapped as 创建请求失败. In Go this almost exclusively means the URL string is invalid; the request was never sent.
Solutions
- Normalize each sourceURL before use: ensure it starts with http:// or https:// (prepend https:// if scheme missing).
- strings.TrimSpace each configured base URL and reject/skip empty entries.
- Validate URLs with url.Parse at config-load time and log invalid mirrors instead of failing at search time.
- Log the composed searchURL on failure to see the exact malformed value.
Example fix
// before
searchURL := fmt.Sprintf("%s/index.php/vod/search/wd/%s.html", strings.TrimRight(baseURL, "/"), url.QueryEscape(keyword))
// after
base := strings.TrimSpace(baseURL)
if !strings.HasPrefix(base, "http://") && !strings.HasPrefix(base, "https://") {
base = "https://" + base
}
searchURL := fmt.Sprintf("%s/index.php/vod/search/wd/%s.html", strings.TrimRight(base, "/"), url.QueryEscape(keyword)) Defensive patterns
Strategy: validation
Validate before calling
u := strings.TrimSpace(baseURL)
if u != "" && !strings.Contains(u, "://") {
u = "https://" + u
}
if _, err := url.Parse(strings.TrimRight(u, "/") + "/index.php/vod/search/wd/test.html"); err != nil {
return fmt.Errorf("invalid search base URL %q: %w", u, err)
} Type guard
func isValidHTTPURL(s string) bool {
u, err := url.Parse(s)
return err == nil && (u.Scheme == "http" || u.Scheme == "https") && u.Host != ""
} Prevention
- Validate mirror URLs with url.Parse at config-load time.
- Always include an explicit http(s) scheme in configured base URLs.
- Trim whitespace/newlines from configuration values.
- Log the fully composed URL when request creation fails.
When it happens
Trigger: baseURL configured with an invalid scheme (missing http:// or https://), containing spaces/control characters, or keyword escaping producing an unparseable URL — http.NewRequestWithContext returns *url.Error which is wrapped here.
Common situations: A mirror entry in config entered as "mysite.com" without a scheme; trailing whitespace or newline in the configured URL; empty baseURL combined with the path format producing "/index.php/...".
Understand the failure class
Background: "Invalid URL" errors: why new URL(), URI.parse, and reqwest::Url reject your string — missing scheme, whitespace, and bad path format — this error's family across 39 libraries.
Related errors
AI-assisted analysis of fish2018/pansou@beaa561337 (2026-09-07).
Data as JSON: /api/errors/d8de7aae33cfbcac.
Report an issue: GitHub.
Appendix: source
Thrown at plugin/shandian/shandian.go:184
// 8. 异步获取详情页信息
enhancedResults := p.enhanceWithDetails(client, results, selectedBase)
// 9. 关键词过滤
return plugin.FilterResultsByKeyword(enhancedResults, keyword), nil
}
func (p *ShandianAsyncPlugin) searchAtBase(client *http.Client, keyword, baseURL string) ([]model.SearchResult, error) {
searchURL := fmt.Sprintf("%s/index.php/vod/search/wd/%s.html", strings.TrimRight(baseURL, "/"), url.QueryEscape(keyword))
// 2. 创建带超时的上下文
ctx, cancel := context.WithTimeout(context.Background(), DefaultTimeout)
defer cancel()
// 3. 创建请求
req, err := http.NewRequestWithContext(ctx, "GET", searchURL, nil)
if err != nil {
return nil, fmt.Errorf("[%s] 创建请求失败: %w", p.Name(), err)
}
// 4. 设置完整的请求头(避免反爬虫)
req.Header.Set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36")
req.Header.Set("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8")
req.Header.Set("Accept-Language", "zh-CN,zh;q=0.9,en;q=0.8")
req.Header.Set("Connection", "keep-alive")
req.Header.Set("Upgrade-Insecure-Requests", "1")
req.Header.Set("Cache-Control", "max-age=0")
req.Header.Set("Referer", strings.TrimRight(baseURL, "/")+"/")
// 5. 发送请求(带重试机制)
resp, err := p.doRequestWithRetry(req, client)
if err != nil {
return nil, fmt.Errorf("[%s] 搜索请求失败: %w", p.Name(), err)
}
defer resp.Body.Close()
View on GitHub (pinned to beaa561337)