fish2018/pansou · error

[ ] 创建请求失败

Error message

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

What it means

searchImpl in the alupan plugin wraps errors from http.NewRequestWithContext when building the GET request to https://www.aliupan.com/?s=<keyword>. With a plain method, an absolute URL, and a nil body, NewRequestWithContext essentially only fails on malformed URL parsing, so this indicates the constructed search URL could not be parsed into a valid *http.Request.

Solutions

  1. Check the exact keyword at runtime — log or inspect it for control/invalid URL characters.
  2. Ensure url.QueryEscape is applied to the keyword in the Sprintf call.
  3. Verify the base URL constant is a valid absolute URL (https://www.aliupan.com/).
  4. Confirm the context passed to NewRequestWithContext is non-nil (it is created on the line above; refactors may have broken that).

Example fix

// before
searchURL := fmt.Sprintf("https://www.aliupan.com/?s=%s", keyword)
// after
searchURL := fmt.Sprintf("https://www.aliupan.com/?s=%s", url.QueryEscape(keyword))
Defensive patterns

Strategy: validation

Validate before calling

// Validate the URL before building the request
u, err := url.Parse(fmt.Sprintf("https://www.aliupan.com/?s=%s", url.QueryEscape(keyword)))
if err != nil {
    return nil, fmt.Errorf("invalid search URL: %w", err)
}
if u.Scheme != "https" || u.Host == "" {
    return nil, fmt.Errorf("unexpected search URL: %s", u)
}

Try / catch

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

Prevention

When it happens

Trigger: http.NewRequestWithContext returns an error — practically only when the formatted URL fails url.Parse (invalid characters/structure) or the context is nil. Since the URL is a fixed template with url.QueryEscape(keyword), this is rare.

Common situations: A code change removes the url.QueryEscape call so the raw keyword produces an invalid URL (e.g. contains spaces or control characters); the base URL string is edited into a malformed literal; a nil context is passed after refactoring.

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/4a30dec0d7681776. Report an issue: GitHub.

Appendix: source

Thrown at plugin/alupan/alupan.go:126

	}
	return &http.Client{
		Transport: transport,
		Timeout:   searchTimeout,
	}
}

func (p *AlupanPlugin) searchImpl(client *http.Client, keyword string, ext map[string]interface{}) ([]model.SearchResult, error) {
	if p.client != nil {
		client = p.client
	}

	searchURL := fmt.Sprintf("https://www.aliupan.com/?s=%s", url.QueryEscape(keyword))
	ctx, cancel := context.WithTimeout(context.Background(), searchTimeout)
	defer cancel()

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

	setCommonHeaders(req, "https://www.aliupan.com/")

	resp, err := p.doRequestWithRetry(req, client, searchMaxRetries)
	if err != nil {
		return nil, fmt.Errorf("[%s] 搜索请求失败: %w", p.Name(), err)
	}
	defer resp.Body.Close()

	if resp.StatusCode != http.StatusOK {
		return nil, fmt.Errorf("[%s] 搜索返回状态码: %d", p.Name(), resp.StatusCode)
	}

	doc, err := goquery.NewDocumentFromReader(resp.Body)
	if err != nil {
		return nil, fmt.Errorf("[%s] 解析搜索页面失败: %w", p.Name(), err)
	}

View on GitHub (pinned to beaa561337)