fish2018/pansou · error

[ ] 搜索请求失败

Error message

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

What it means

ash's searchImpl calls doRequestWithRetry, which exhausts its retry attempts on the GET request to the ASH search endpoint. The final transport error is wrapped as '搜索请求失败'. It indicates the retries could not obtain a response at all (connection-level failure), distinct from a non-200 status (see error 33).

Solutions

  1. Unwrap the error (errors.Unwrap) to identify the root transport failure (timeout vs refused vs TLS).
  2. Test the ASH endpoint directly with curl to check availability and latency.
  3. Increase the 15s context timeout or the retry count/backoff if the site is merely slow.
  4. Configure an HTTP(S) proxy if the environment requires one, and verify DNS resolution.

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 {
    log.Printf("[%s] search failed: %v", p.Name(), errors.Unwrap(err))
    return nil, fmt.Errorf("[%s] 搜索请求失败: %w", p.Name(), err)
}
Defensive patterns

Strategy: retry

Validate before calling

// pre-check reachability
resp, err := http.Head(baseURL); if err != nil { /* upstream down, skip search */ }

Try / catch

err := doSearch(); if err != nil {
    if errors.Is(err, context.DeadlineExceeded) {
        // retry with larger timeout
    } else if isConnRefused(err) {
        // fail fast, don't retry
    }
}

Prevention

When it happens

Trigger: p.doRequestWithRetry(req, client) returns an error after all attempts fail — connection refused/reset, DNS failure, TLS handshake error, or request context (15s timeout) expiry — ash.go:93.

Common situations: Upstream site is offline or geo-blocked; local network/proxy misconfigured; the 15-second context times out on a slow site; server drops keep-alive connections mid-retry.

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

Appendix: source

Thrown at plugin/ash/ash.go:93

	searchURL := fmt.Sprintf("https://so.allsharehub.com/s/%s.html", url.QueryEscape(keyword))
	
	// 创建带超时的上下文(减少超时时间,提高响应速度)
	ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second)
	defer cancel()
	
	// 创建请求
	req, err := http.NewRequestWithContext(ctx, "GET", searchURL, nil)
	if err != nil {
		return nil, fmt.Errorf("[%s] 创建请求失败: %w", p.Name(), err)
	}
	
	// 设置请求头
	p.setRequestHeaders(req)
	
	// 发送请求(优化重试)
	resp, err := p.doRequestWithRetry(req, client)
	if err != nil {
		return nil, fmt.Errorf("[%s] 搜索请求失败: %w", p.Name(), err)
	}
	defer resp.Body.Close()
	
	// 检查状态码
	if resp.StatusCode != 200 {
		return nil, fmt.Errorf("[%s] 请求返回状态码: %d", p.Name(), resp.StatusCode)
	}
	
	// 读取响应(使用有限制的读取,避免读取过大内容)
	// ASH页面通常不会太大,限制在2MB以内
	limitReader := io.LimitReader(resp.Body, 2*1024*1024)
	body, err := io.ReadAll(limitReader)
	if err != nil {
		return nil, fmt.Errorf("[%s] 读取响应失败: %w", p.Name(), err)
	}
	
	// 从HTML中提取JSON数据(直接传递字节,避免字符串转换)
	results, err := p.extractResultsFromBytes(body)

View on GitHub (pinned to beaa561337)