fish2018/pansou · error

[ ] 搜索 API 请求失败

Error message

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

What it means

searchImpl sends the search API request through doRequestWithRetry; when even the retrying client fails, the plugin falls back to HTML search via searchWeb, attaching this wrapped error as the apiErr context. It means the JSON API endpoint was unreachable or errored.

Solutions

  1. Inspect the wrapped cause from doRequestWithRetry
  2. Confirm the API host resolves and is reachable (curl the searchURL)
  3. Verify DefaultTimeout is generous enough for the upstream
  4. Rely on/verify the searchWeb HTML fallback results

Example fix

// before
resp, err := p.doRequestWithRetry(req, client)
if err != nil {
    return p.searchWeb(client, keyword, fmt.Errorf("[%s] 搜索 API 请求失败: %w", p.Name(), err))
}
// after
resp, err := p.doRequestWithRetry(req, client)
if err != nil {
    log.Printf("feikuai API request failed, falling back to web: %v", err)
    return p.searchWeb(client, keyword, fmt.Errorf("[%s] 搜索 API 请求失败: %w", p.Name(), err))
}
Defensive patterns

Strategy: fallback

Validate before calling

// probe API endpoint before relying on it
resp, err := client.Head(apiBaseURL)
_ = err // if err != nil, expect searchWeb fallback path

Try / catch

results, err := plugin.Search(keyword)
if err != nil && strings.Contains(err.Error(), "搜索 API 请求失败") {
    log.Printf("feikuai API down, web fallback also attempted: %v", err)
    // surface partial info; the error already embeds the API cause
}

Prevention

When it happens

Trigger: doRequestWithRetry returns non-nil (transport error, timeout, exhausted retries) for the API GET request.

Common situations: API domain blocked or DNS-poisoned, TLS errors after a site domain change, timeouts under DefaultTimeout, upstream API temporarily down.

Understand the failure class

Background: "API request failed": what wrapped HTTP errors from external APIs mean and how to find the real cause — this error's family across 29 libraries.

Related errors


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

Appendix: source

Thrown at plugin/feikuai/feikuai.go:127

	defer cancel()

	// 创建请求
	req, err := http.NewRequestWithContext(ctx, "GET", searchURL, nil)
	if err != nil {
		return nil, fmt.Errorf("[%s] 创建请求失败: %w", p.Name(), err)
	}

	// 设置请求头
	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", "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("Referer", "https://feikuai.tv/")

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

	// 检查状态码
	if resp.StatusCode != 200 {
		return p.searchWeb(client, keyword, fmt.Errorf("[%s] 搜索 API 返回状态码: %d", p.Name(), resp.StatusCode))
	}

	// 读取并解析JSON响应
	body, err := io.ReadAll(resp.Body)
	if err != nil {
		return p.searchWeb(client, keyword, fmt.Errorf("[%s] 读取 API 响应失败: %w", p.Name(), err))
	}

	var apiResp FeikuaiAPIResponse
	if err := json.Unmarshal(body, &apiResp); err != nil {
		return p.searchWeb(client, keyword, fmt.Errorf("[%s] API JSON 解析失败: %w", p.Name(), err))
	}

View on GitHub (pinned to beaa561337)