fish2018/pansou · error

[ ] 创建搜索请求失败

Error message

[%s] 创建搜索请求失败: %w

What it means

executeSearch wraps the error from http.NewRequestWithContext when building the POST request to the search endpoint. As with the token request, method/URL/body are constructed from constants and the token/keyword, so failure indicates the composed searchURL is not a valid URL. searchImpl aborts before any network I/O.

Solutions

  1. Log the composed searchURL and validate with url.Parse before constructing the request
  2. URL-escape the keyword (url.QueryEscape) and the token before interpolating into the query string
  3. Verify BaseURL and the search path format string in executeSearch are intact

Example fix

// before
searchURL := fmt.Sprintf("%s%s?DToken2=%s&...&wd=%s&...", BaseURL, searchPath, token, keyword)
// after
searchURL := fmt.Sprintf("%s%s?DToken2=%s&...&wd=%s&...", BaseURL, searchPath, url.QueryEscape(token), url.QueryEscape(keyword))
Defensive patterns

Strategy: validation

Validate before calling

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

Try / catch

if err != nil {
    return nil, fmt.Errorf("search request build failed: %w", err)
}

Prevention

When it happens

Trigger: http.NewRequestWithContext(ctx, "POST", searchURL, nil) errors — the fmt.Sprintf-composed searchURL (BaseURL + query string with DToken2/keyword interpolated) is malformed, e.g. unescaped control characters in the keyword.

Common situations: Search keyword containing raw newlines/control characters injected into the query string; BaseURL constant misconfigured; token value containing characters that break the 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/14843833cef67634. Report an issue: GitHub.

Appendix: source

Thrown at plugin/xys/xys.go:248

		lastErr = err
	}
	
	return nil, fmt.Errorf("[%s] 重试 %d 次后仍然失败: %w", p.Name(), maxRetries, lastErr)
}

// executeSearch 执行搜索请求
func (p *XysPlugin) executeSearch(client *http.Client, token, keyword string) ([]model.SearchResult, error) {
	// 构建搜索URL
	searchURL := fmt.Sprintf("%s%s?DToken2=%s&requestID=undefined&mode=90002&stype=undefined&scope_content=0&wd=%s&uk=&page=1&limit=20&screen_filetype=",
		BaseURL, SearchPath, token, url.QueryEscape(keyword))

	// 创建带超时的上下文
	ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
	defer cancel()

	req, err := http.NewRequestWithContext(ctx, "POST", searchURL, nil)
	if err != nil {
		return nil, fmt.Errorf("[%s] 创建搜索请求失败: %w", p.Name(), err)
	}

	// 设置完整的请求头
	req.Header.Set("User-Agent", UserAgent)
	req.Header.Set("Accept", "application/json, text/plain, */*")
	req.Header.Set("Accept-Language", "zh-CN,zh;q=0.9,en;q=0.8")
	req.Header.Set("Connection", "keep-alive")
	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
	req.Header.Set("Referer", BaseURL+"/")
	req.Header.Set("Origin", BaseURL)
	req.Header.Set("X-Requested-With", "XMLHttpRequest")

	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)