fish2018/pansou · error
创建GET请求失败
Error message
创建GET请求失败: %w
What it means
xdpan's fetchSearchResults builds the search GET request with http.NewRequestWithContext. If request construction fails (invalid method/URL, unparsable target), it wraps the error as this message. With a fixed 'GET' method this almost always means the assembled search URL is invalid.
Solutions
- Verify the xdpan baseURL configuration is set and is a valid absolute HTTP(S) URL.
- Trim whitespace/newlines from the configured base URL before use.
- Log the final searchURL to spot malformed composition (double schemes, missing host).
- Sanitize/strictly escape the keyword before inserting it into the query string.
Example fix
// before
searchURL := fmt.Sprintf("%s/search?page=1&k=%s&p=baidu", strings.TrimRight(p.baseURL, "/"), url.QueryEscape(keyword))
// after: validate the base URL first
base := strings.TrimSpace(strings.TrimRight(p.baseURL, "/"))
if u, err := url.Parse(base); err != nil || u.Scheme == "" || u.Host == "" {
return nil, fmt.Errorf("无效的baseURL配置: %q", p.baseURL)
}
searchURL := fmt.Sprintf("%s/search?page=1&k=%s&p=baidu", base, url.QueryEscape(keyword)) Defensive patterns
Strategy: validation
Validate before calling
u, err := url.Parse(cfg.BaseURL)
if err != nil || u.Scheme == "" || u.Host == "" {
return fmt.Errorf("invalid baseURL: %q", cfg.BaseURL)
} Try / catch
results, err := pluginSearch(keyword)
if err != nil && strings.Contains(err.Error(), "创建GET请求失败") {
// invalid URL — check and correct baseURL config before retrying
} Prevention
- Validate baseURL at plugin startup, not per-request.
- Trim whitespace/newlines from config values.
- Escape keywords with url.QueryEscape before composing URLs.
When it happens
Trigger: http.NewRequestWithContext returns an error because the searchURL '%s/search?page=1&k=%s&p=baidu' is malformed — e.g. baseURL is empty, contains whitespace/control characters, or the URL-escaped keyword produced an invalid URL string.
Common situations: Missing or misconfigured xdpan baseURL (empty config field); trailing newline in a config value; keyword containing raw control characters; programmatic use passing a non-URL base.
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/4a946c5cfe8a9374.
Report an issue: GitHub.
Appendix: source
Thrown at plugin/xdpan/xdpan.go:103
filteredResults := plugin.FilterResultsByKeyword(searchResults, keyword)
if DebugLog {
fmt.Printf("[xdpan] 关键词过滤后: 过滤前=%d, 过滤后=%d\n", len(searchResults), len(filteredResults))
}
return filteredResults, nil
}
// fetchSearchResults 获取搜索结果
func (p *XdpanPlugin) fetchSearchResults(client *http.Client, keyword string) ([]model.SearchResult, error) {
// 构建搜索URL(只获取第一页)
searchURL := fmt.Sprintf("%s/search?page=1&k=%s&p=baidu", strings.TrimRight(p.baseURL, "/"), url.QueryEscape(keyword))
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
req, err := http.NewRequestWithContext(ctx, "GET", searchURL, nil)
if err != nil {
return nil, fmt.Errorf("创建GET请求失败: %w", err)
}
p.setRequestHeaders(req)
if DebugLog {
fmt.Printf("[xdpan] 搜索URL: %s\n", searchURL)
}
resp, err := p.doRequestWithRetry(req, client)
if err != nil {
return nil, fmt.Errorf("GET请求失败: %w", err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("请求返回状态码: %d", resp.StatusCode)
}
View on GitHub (pinned to beaa561337)