fish2018/pansou · error
[ ] 创建请求失败
Error message
[%s] 创建请求失败: %w
What it means
This error wraps a failure from http.NewRequestWithContext while building the GET request to the duoduo search URL inside searchImpl. In practice this only fails when the URL string cannot be parsed or the context is invalid, since no network I/O happens here. The plugin wraps the underlying err so the plugin name and root cause are preserved in the message.
Solutions
- Print/log the exact searchURL string before http.NewRequestWithContext and fix malformed characters.
- Wrap dynamic parts with url.QueryEscape: searchURL := baseURL + "?q=" + url.QueryEscape(keyword).
- Use url.Parse on the constructed URL to validate it before issuing the request.
- Verify the configured site base URL is current and correct.
Example fix
// before
searchURL := fmt.Sprintf("%s/vodsearch/-------------.html?wd=%s", base, keyword)
req, err := http.NewRequestWithContext(ctx, "GET", searchURL, nil)
// after
searchURL := fmt.Sprintf("%s/vodsearch/-------------.html?wd=%s", base, url.QueryEscape(keyword))
if _, perr := url.Parse(searchURL); perr != nil { return nil, perr }
req, err := http.NewRequestWithContext(ctx, "GET", searchURL, nil) Defensive patterns
Strategy: validation
Validate before calling
func validateSearchURL(base, keyword string) error {
if base == "" { return fmt.Errorf("base URL 为空") }
u := base + "?wd=" + url.QueryEscape(keyword)
_, err := url.Parse(u)
return err
} Type guard
func isValidURL(s string) bool {
u, err := url.Parse(s)
return err == nil && u.Scheme != "" && u.Host != ""
} Prevention
- Always url.QueryEscape user-supplied keywords.
- Validate composed URLs with url.Parse before issuing requests.
- Keep base URLs in configuration, not hardcoded strings.
- Add a startup self-test that builds a sample search URL.
When it happens
Trigger: searchURL passed to http.NewRequestWithContext is malformed (e.g. contains spaces, unescaped characters, or is empty because the configured base URL is wrong or the search keyword was not URL-encoded).
Common situations: Base URL misconfigured or site domain changed and someone hand-builds a URL with raw CJK/keyword characters; keyword not passed through url.QueryEscape; empty search term producing a truncated URL.
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/57df58a6d846a694.
Report an issue: GitHub.
Appendix: source
Thrown at plugin/duoduo/duoduo.go:164
atomic.AddInt64(&totalSearchTime, duration)
}()
// 使用优化的客户端
if p.optimizedClient != nil {
client = p.optimizedClient
}
// 1. 构建搜索URL
searchURL := fmt.Sprintf("https://tv.yydsys.top/index.php/vod/search/wd/%s.html", 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", "https://tv.yydsys.top/")
// 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)