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

  1. Print/log the exact searchURL string before http.NewRequestWithContext and fix malformed characters.
  2. Wrap dynamic parts with url.QueryEscape: searchURL := baseURL + "?q=" + url.QueryEscape(keyword).
  3. Use url.Parse on the constructed URL to validate it before issuing the request.
  4. 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

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)