fish2018/pansou · error

创建请求失败

Error message

创建请求失败: %w

What it means

doSearch builds a GET request to the susu search URL with a 30s context; if http.NewRequestWithContext returns an error, it is wrapped as 创建请求失败 (request creation failed). In Go this only happens for an invalid method/URL or a nil/already-done context — here essentially always a malformed searchURL.

Solutions

  1. Build the query with url.Values.Encode() so the keyword is properly escaped
  2. Print searchURL on failure to identify the malformed part and fix BaseURL or keyword encoding
  3. Validate BaseURL with url.Parse at plugin startup to fail fast

Example fix

// before
searchURL := BaseURL + "/search?keyword=" + keyword
req, err := http.NewRequestWithContext(ctx, http.MethodGet, searchURL, nil)
if err != nil {
    return nil, fmt.Errorf("创建请求失败: %w", err)
}
// after
searchURL := BaseURL + "/search?" + url.Values{"keyword": {keyword}}.Encode()
req, err := http.NewRequestWithContext(ctx, http.MethodGet, searchURL, nil)
if err != nil {
    return nil, fmt.Errorf("创建请求失败 (url=%s): %w", searchURL, err)
}
Defensive patterns

Strategy: validation

Validate before calling

u, err := url.Parse(searchURL)
if err != nil || u.Scheme == "" || u.Host == "" {
    return fmt.Errorf("invalid searchURL %q", searchURL)
}

Try / catch

results, err := doSearch(keyword)
if err != nil && strings.Contains(err.Error(), "创建请求失败") {
    return fmt.Errorf("check BaseURL and keyword encoding: %w", err)
}

Prevention

When it happens

Trigger: searchURL is malformed: BaseURL is misconfigured (invalid scheme/host) or the query string built from the keyword contains unescaped invalid characters.

Common situations: Typo'd or empty BaseURL constant; keyword with raw spaces or special characters interpolated without url.QueryEscape; configuration injection of a bad proxy/base URL.

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/3701a1481e320e5f. Report an issue: GitHub.

Appendix: source

Thrown at plugin/susu/susu.go:151

}

// SearchWithResult 执行搜索并返回包含IsFinal标记的结果
func (p *SusuAsyncPlugin) SearchWithResult(keyword string, ext map[string]interface{}) (model.PluginSearchResult, error) {
	return p.AsyncSearchWithResult(keyword, p.doSearch, p.MainCacheKey, ext)
}

// doSearch 实际的搜索实现
func (p *SusuAsyncPlugin) doSearch(client *http.Client, keyword string, ext map[string]interface{}) ([]model.SearchResult, error) {
	// 构建搜索URL
	searchURL := fmt.Sprintf(SearchURL, url.QueryEscape(keyword))

	// 发送请求
	ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
	defer cancel()

	req, err := http.NewRequestWithContext(ctx, http.MethodGet, searchURL, nil)
	if err != nil {
		return nil, fmt.Errorf("创建请求失败: %w", err)
	}

	// 设置请求头
	req.Header.Set("User-Agent", getRandomUA())
	setBrowserHeaders(req, BaseURL+"/")

	// 发送请求(带重试)
	resp, err := p.doRequestWithRetry(client, req, MaxRetries)
	if err != nil {
		return nil, fmt.Errorf("请求失败: %w", err)
	}
	defer resp.Body.Close()
	if resp.StatusCode != http.StatusOK {
		return nil, fmt.Errorf("[susu] 搜索请求返回状态码: %d", resp.StatusCode)
	}

	// 解析HTML
	doc, err := goquery.NewDocumentFromReader(resp.Body)

View on GitHub (pinned to beaa561337)