fish2018/pansou · error

[ ] 搜索请求失败

Error message

[%s] 搜索请求失败: %w

What it means

jutoushe searchImpl wraps the error returned by doRequestWithRetry — meaning the HTTP request to the site failed after all internal retries (connection errors, TLS errors, timeouts). The wrapped lastErr explains the network-level cause.

Solutions

  1. Inspect the wrapped error for the root cause (dial tcp / timeout / x509)
  2. Test connectivity to the site from the host (curl baseURL)
  3. Increase the 30s context timeout if on slow networks
  4. Check whether the site is blocking the User-Agent/IP and adjust headers or use a proxy

Example fix

// before
resp, err := p.doRequestWithRetry(req, client)
if err != nil { return nil, fmt.Errorf("[%s] 搜索请求失败: %w", p.Name(), err) }
// after
resp, err := p.doRequestWithRetry(req, client)
if err != nil {
    var ne net.Error
    if errors.As(err, &ne) && ne.Timeout() {
        return nil, fmt.Errorf("[%s] search timed out: %w", p.Name(), err)
    }
    return nil, fmt.Errorf("[%s] 搜索请求失败: %w", p.Name(), err)
}
Defensive patterns

Strategy: retry

Validate before calling

conn, err := net.DialTimeout("tcp", "www.jutoushe.cc:443", 5*time.Second)
if err != nil { return fmt.Errorf("site unreachable before search: %w", err) }
conn.Close()

Try / catch

results, err := plugin.Search(keyword)
if err != nil {
    var ne net.Error
    if errors.As(err, &ne) && ne.Timeout() {
        return retryLater(err) // back off and retry later
    }
    return err
}

Prevention

When it happens

Trigger: p.doRequestWithRetry(req, client) exhausts its retries: server unreachable, DNS failure, TLS handshake error, or context timeout (30s) expires mid-flight.

Common situations: Target site blocked or down; no internet/DNS in the deployment environment; site rate-limiting the scraper's IP; 30s context too short on slow networks.

Understand the failure class

Background: 'Something went wrong' / 'Request failed (500)' / 'HTTP error! status: 404' — what failed HTTP requests actually mean and how to find the real cause — this error's family across 28 libraries.

Related errors


AI-assisted analysis of fish2018/pansou@beaa561337 (2026-09-07). Data as JSON: /api/errors/9bc82d38f4e88162. Report an issue: GitHub.

Appendix: source

Thrown at plugin/jutoushe/jutoushe.go:70

	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("Referer", baseURL+"/")

	// 5. 发送HTTP请求(带重试机制)
	resp, err := p.doRequestWithRetry(req, client)
	if err != nil {
		return nil, fmt.Errorf("[%s] 搜索请求失败: %w", p.Name(), err)
	}
	defer resp.Body.Close()

	// 6. 检查状态码
	if resp.StatusCode != 200 {
		return nil, fmt.Errorf("[%s] 请求返回状态码: %d", p.Name(), resp.StatusCode)
	}

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

	// 8. 提取搜索结果
	var results []model.SearchResult
	doc.Find("ul.erx-list li.item").Each(func(i int, s *goquery.Selection) {
		// 提取标题和链接

View on GitHub (pinned to beaa561337)