fish2018/pansou · error

创建请求失败

Error message

创建请求失败: %w

What it means

pan666's fetchPage fails when http.NewRequest("GET", apiURL, nil) returns an error while building the search URL (BaseURL + filter[q]/include/page parameters). This only happens with a malformed URL (bad BaseURL, unescaped control characters in the query) — keyword itself is escaped with url.QueryEscape, so the cause is almost always configuration-level.

Solutions

  1. Print the constructed apiURL and validate it parses (url.Parse) before creating the request
  2. Check the BaseURL value has scheme https:// and no stray whitespace
  3. Keep url.QueryEscape(keyword) applied to all user-supplied query components
  4. Use url.Values.Encode() to build the query string instead of manual fmt.Sprintf

Example fix

// before
apiURL := fmt.Sprintf("%s?filter[q]=%s&include=mostRelevantPost&page[offset]=%d&page[limit]=%d",
    BaseURL, url.QueryEscape(keyword), offset, PageSize)
req, err := http.NewRequest("GET", apiURL, nil)
// after
q := url.Values{}
q.Set("filter[q]", keyword)
q.Set("include", "mostRelevantPost")
q.Set("page[offset]", fmt.Sprint(offset))
q.Set("page[limit]", fmt.Sprint(PageSize))
req, err := http.NewRequest("GET", BaseURL+"?"+q.Encode(), nil)
Defensive patterns

Strategy: validation

Validate before calling

func validateBaseURL(raw string) error {
    u, err := url.Parse(strings.TrimSpace(raw))
    if err != nil { return err }
    if u.Scheme != "https" || u.Host == "" {
        return fmt.Errorf("BaseURL must be absolute https URL, got %q", raw)
    }
    return nil
}

Try / catch

if err != nil {
    return fmt.Errorf("build request: %w (url was %q)", err, apiURL)
}

Prevention

When it happens

Trigger: fetchPage constructs apiURL from BaseURL and calls http.NewRequest; err is non-nil when BaseURL is empty/invalid or contains characters Go's URL parser rejects (spaces, invalid scheme, control chars).

Common situations: BaseURL constant changed to a value with a typo or missing scheme; BaseURL loaded from config containing trailing whitespace/newline; keyword containing characters that survive to break the URL after a refactor removed QueryEscape.

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

Appendix: source

Thrown at plugin/pan666/pan666.go:185

	
	// 按时间降序排序
	sort.Slice(unique, func(i, j int) bool {
		return unique[i].Datetime.After(unique[j].Datetime)
	})
	
	return unique
}

// fetchPage 获取指定页的搜索结果
func (p *Pan666AsyncPlugin) fetchPage(client *http.Client, keyword string, offset int) ([]model.SearchResult, bool, error) {
	// 构建API URL
	apiURL := fmt.Sprintf("%s?filter[q]=%s&include=mostRelevantPost&page[offset]=%d&page[limit]=%d",
		BaseURL, url.QueryEscape(keyword), offset, PageSize)
	
	// 创建请求
	req, err := http.NewRequest("GET", apiURL, nil)
	if err != nil {
		return nil, false, fmt.Errorf("创建请求失败: %w", err)
	}
	
	// 设置请求头
	req.Header.Set("User-Agent", getRandomUA())
	req.Header.Set("X-Forwarded-For", generateRandomIP())
	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("Sec-Fetch-Dest", "empty")
	req.Header.Set("Sec-Fetch-Mode", "cors")
	req.Header.Set("Sec-Fetch-Site", "same-origin")
	
	var resp *http.Response
	var responseBody []byte
	
	// 重试逻辑
	for i := 0; i <= p.retries; i++ {
		// 发送请求

View on GitHub (pinned to beaa561337)