fish2018/pansou · error

[ ] 创建第 页请求失败

Error message

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

What it means

fetchPage in the yunsou plugin failed while constructing the GET request for a search results page via http.NewRequestWithContext. The error is prefixed with the plugin name and page number. Since the URL is built from a template with a keyword-derived path, this usually means the URL is malformed (e.g. special characters in the keyword path) or the context is already canceled.

Solutions

  1. URL-escape pathKeyword with url.PathEscape before formatting into the template
  2. Log requestURL on failure to spot malformed construction
  3. Check ctx.Err() before building the request
  4. Validate searchURLTemplate is a valid absolute URL

Example fix

// before
path = fmt.Sprintf("%s-%d", pathKeyword, page)
requestURL := fmt.Sprintf(searchURLTemplate, path)
req, err := http.NewRequestWithContext(ctx, http.MethodGet, requestURL, nil)
if err != nil {
    return nil, fmt.Errorf("[%s] 创建第%d页请求失败: %w", p.Name(), page, err)
}
// after
path = fmt.Sprintf("%s-%d", url.PathEscape(pathKeyword), page)
requestURL := fmt.Sprintf(searchURLTemplate, path)
if _, perr := url.Parse(requestURL); perr != nil {
    return nil, fmt.Errorf("[%s] invalid page %d url %q: %w", p.Name(), page, requestURL, perr)
}
req, err := http.NewRequestWithContext(ctx, http.MethodGet, requestURL, nil)
if err != nil {
    return nil, fmt.Errorf("[%s] 创建第%d页请求失败: %w", p.Name(), page, err)
}
Defensive patterns

Strategy: validation

Validate before calling

if strings.TrimSpace(pathKeyword) == "" {
    return errors.New("keyword path required")
}
esccaped := url.PathEscape(pathKeyword)
requestURL := fmt.Sprintf(searchURLTemplate, esccaped)
if _, err := url.Parse(requestURL); err != nil {
    return fmt.Errorf("invalid request url: %w", err)
}

Type guard

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

Try / catch

items, err := fetchPage(ctx, client, keyword, page)
if err != nil && strings.Contains(err.Error(), "创建第") {
    log.Error("yunsou page request construction failed", "page", page, "err", err)
    return nil, err
}

Prevention

When it happens

Trigger: http.NewRequestWithContext fails building the request to searchURLTemplate with pathKeyword (and -page suffix) — invalid URL characters from an unescaped keyword, or an invalid/canceled ctx.

Common situations: Keywords containing spaces, slashes, or CJK characters placed into a path without escaping; a canceled parent context; a mistyped searchURLTemplate constant.

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/69bbd9101c9f158c. Report an issue: GitHub.

Appendix: source

Thrown at plugin/yunsou/yunsou.go:121

		}
		results = append(results, p.parseSearchResults(pageDoc)...)
	}
	if len(results) > maxResults {
		results = results[:maxResults]
	}
	return plugin.FilterResultsByKeyword(results, keyword), nil
}

func (p *YunsouAsyncPlugin) fetchPage(ctx context.Context, client *http.Client, keyword string, page int) (*goquery.Document, error) {
	pathKeyword := url.PathEscape(keyword)
	path := pathKeyword
	if page > 1 {
		path = fmt.Sprintf("%s-%d", pathKeyword, page)
	}
	requestURL := fmt.Sprintf(searchURLTemplate, path)
	req, err := http.NewRequestWithContext(ctx, http.MethodGet, requestURL, nil)
	if err != nil {
		return nil, fmt.Errorf("[%s] 创建第%d页请求失败: %w", p.Name(), page, err)
	}
	req.Header.Set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36")
	req.Header.Set("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8")
	req.Header.Set("Accept-Language", "zh-CN,zh;q=0.9,en;q=0.8")
	req.Header.Set("Referer", "https://wpys.cc/")
	resp, err := p.doRequestWithRetry(req, client)
	if err != nil {
		return nil, fmt.Errorf("[%s] 第%d页搜索请求失败: %w", p.Name(), page, err)
	}
	defer resp.Body.Close()
	doc, err := goquery.NewDocumentFromReader(resp.Body)
	if err != nil {
		return nil, fmt.Errorf("[%s] 解析第%d页失败: %w", p.Name(), page, err)
	}
	return doc, nil
}

func (p *YunsouAsyncPlugin) doRequestWithRetry(req *http.Request, client *http.Client) (*http.Response, error) {

View on GitHub (pinned to beaa561337)