fish2018/pansou · error
[ ] 搜索请求失败
Error message
[%s] 搜索请求失败: %w
What it means
searchImpl wraps any error returned by doRequestWithRetry for the alupan search request. It means the HTTP GET to www.aliupan.com failed on every retry attempt — network-level failure or timeout — before any response body could be processed. The underlying cause is preserved via %w.
Solutions
- Inspect the wrapped error (errors.Is for context.DeadlineExceeded, *net.OpError, etc.) to identify the root cause.
- Test reachability: curl -v 'https://www.aliupan.com/?s=test' from the deployment host; check proxy env vars.
- Increase searchTimeout (currently 12s) or searchMaxRetries (3) if failures are transient/slow-network.
- Check for anti-bot/Cloudflare challenges; add appropriate headers or cookies in setCommonHeaders if the site began blocking.
- Fall back gracefully — skip this plugin and aggregate results from other plugins when it fails.
Example fix
// before
resp, err := p.doRequestWithRetry(req, client, searchMaxRetries)
// after
resp, err := p.doRequestWithRetry(req, client, searchMaxRetries)
if errors.Is(err, context.DeadlineExceeded) {
// bump searchTimeout or retry with a fresh context
} Defensive patterns
Strategy: retry
Validate before calling
// Quick pre-flight before running the full search
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
defer cancel()
req, _ := http.NewRequestWithContext(ctx, http.MethodHead, "https://www.aliupan.com/", nil)
if _, err := http.DefaultClient.Do(req); err != nil {
log.Printf("aliupan unreachable: %v", err) // skip plugin or alert
} Try / catch
// Go: classify the wrapped transport error and fall back
if err != nil {
switch {
case errors.Is(err, context.DeadlineExceeded):
log.Println("aliupan: request timed out after retries")
case errors.Is(err, syscall.ECONNREFUSED):
log.Println("aliupan: connection refused")
default:
log.Printf("aliupan: request failed: %v", err)
}
// continue with other plugins' results
} Prevention
- Keep searchTimeout and retry counts sized to the site's real latency.
- Test egress (curl) from the deployment environment, including proxy settings.
- Update User-Agent/Referer headers when the site tightens bot protection.
- Degrade gracefully: aggregate other plugins' results instead of failing the whole search.
When it happens
Trigger: doRequestWithRetry exhausts searchMaxRetries (3) because of DNS failure, connection refused/reset, TLS handshake timeout, or the 12-second searchTimeout context/client deadline expiring on each attempt.
Common situations: aliupan.com is down, geo-blocked, or rate-limiting the host; the deployment environment has no internet egress; a corporate proxy intercepts HTTPS; the 12s timeout is too short on a slow connection; site started requiring cookies/JS challenge (Cloudflare).
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/c7bd876263f795da.
Report an issue: GitHub.
Appendix: source
Thrown at plugin/alupan/alupan.go:133
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)
}
var (
results []model.SearchResult
wg sync.WaitGroup
mu sync.Mutex
sem = make(chan struct{}, maxConcurrency)
)View on GitHub (pinned to beaa561337)