fish2018/pansou · error
[ ] 创建请求失败
Error message
[%s] 创建请求失败: %w
What it means
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).
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.
Example fix
// before
searchURL := "https://www.ahhhhfs.com/?s=" + keyword
req, err := http.NewRequestWithContext(ctx, "GET", searchURL, nil)
if err != nil {
return nil, fmt.Errorf("[%s] 创建请求失败: %w", p.Name(), err)
}
// after
searchURL := "https://www.ahhhhfs.com/?s=" + url.QueryEscape(keyword)
req, err := http.NewRequestWithContext(ctx, "GET", searchURL, nil)
if err != nil {
return nil, fmt.Errorf("[%s] 创建请求失败: %w", p.Name(), err)
} Defensive patterns
Strategy: validation
Validate before calling
searchURL := "https://www.ahhhhfs.com/?s=" + url.QueryEscape(keyword)
if u, err := url.Parse(searchURL); err != nil || u.Host == "" {
return fmt.Errorf("非法搜索URL: %q", searchURL)
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Understand the failure class
Background: "Invalid URL" / "URL cannot be empty": fix the malformed or missing URL behind request-construction failures — this error's family across 50 libraries.
Related errors
AI-assisted analysis of fish2018/pansou@beaa561337 (2026-09-07).
Data as JSON: /api/errors/f2e01ff9b0097da9.
Report an issue: GitHub.
Appendix: source
Thrown at plugin/ahhhhfs/ahhhhfs.go:166
fmt.Printf("[%s] 搜索耗时: %v\n", p.Name(), time.Since(start))
}()
// 使用优化的客户端
if p.optimizedClient != nil {
client = p.optimizedClient
}
// 1. 构建搜索URL
searchURL := fmt.Sprintf("https://www.ahhhhfs.com/?cat=&s=%s", 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/120.0.0.0 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", "https://www.ahhhhfs.com/")
// 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)