fish2018/pansou · error

[ ] 创建请求失败

Error message

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

What it means

dy4k's searchPage wraps a failure from http.NewRequestWithContext when constructing the GET request for one search results page. As with the duoduo plugin, this fires only when the page URL is unparseable or the context is invalid — before any network traffic. The plugin name is included for multi-source disambiguation.

Solutions

  1. Log searchURL before creating the request and inspect it for unescaped characters.
  2. Escape the keyword with url.QueryEscape when building the URL.
  3. Validate the composed URL with url.Parse before http.NewRequestWithContext.
  4. Confirm the configured base URL for dy4k is correct and reachable.

Example fix

// before
searchURL := fmt.Sprintf("%s/search/%s/%d", base, keyword, page)
req, err := http.NewRequestWithContext(ctx, "GET", searchURL, nil)
// after
searchURL := fmt.Sprintf("%s/search/%s/%d", base, url.QueryEscape(keyword), page)
if _, perr := url.Parse(searchURL); perr != nil {
    return nil, 0, fmt.Errorf("[%s] 无效搜索URL: %w", p.Name(), perr)
}
req, err := http.NewRequestWithContext(ctx, "GET", searchURL, nil)
Defensive patterns

Strategy: validation

Validate before calling

func buildSearchURL(base, keyword string, page int) (string, error) {
    u := fmt.Sprintf("%s/search/%s/%d", base, url.QueryEscape(keyword), page)
    parsed, err := url.Parse(u)
    if err != nil { return "", err }
    if parsed.Scheme == "" || parsed.Host == "" { return "", fmt.Errorf("invalid url: %s", u) }
    return u, nil
}

Type guard

func validRequestURL(s string) bool {
    u, err := url.Parse(s)
    return err == nil && (u.Scheme == "http" || u.Scheme == "https") && u.Host != ""
}

Prevention

When it happens

Trigger: The per-page searchURL built from the base URL, keyword, and page number is malformed (unescaped CJK keyword characters, spaces, or empty base URL), making http.NewRequestWithContext return an error.

Common situations: Keyword contains characters that were not url.QueryEscape'd; configuration changed the base URL to something invalid; page number formatting produced a URL with an unexpected token; empty keyword yields a path-only URL that trips parsing in edge cases.

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/15d83b5d59d478e9. Report an issue: GitHub.

Appendix: source

Thrown at plugin/dy4k/dy4k.go:357

	// 1. 构建搜索URL
	var searchURL string
	if page == 1 {
		searchURL = fmt.Sprintf(SearchURL, encodedKeyword)
	} else {
		searchURL = fmt.Sprintf(SearchPageURL, encodedKeyword, page)
	}

	debugPrintf("🔧 [Dy4k DEBUG] 构建的URL: %s\n", searchURL)

	// 2. 创建带超时的上下文
	ctx, cancel := context.WithTimeout(context.Background(), DefaultTimeout)
	defer cancel()

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

	// 4. 设置完整的请求头(包含随机UA和IP)
	randomUA := getRandomUA()
	randomIP := generateRandomIP()

	req.Header.Set("User-Agent", randomUA)
	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", BaseURL+"/")
	req.Header.Set("X-Forwarded-For", randomIP)
	req.Header.Set("X-Real-IP", randomIP)
	req.Header.Set("sec-ch-ua-platform", "macOS")

	debugPrintf("🔧 [Dy4k DEBUG] 使用随机UA: %s\n", randomUA)

View on GitHub (pinned to beaa561337)