fish2018/pansou · critical
[ ] API 失败且网页搜索请求失败: (API: )
Error message
[%s] API 失败且网页搜索请求失败: %v (API: %v)
What it means
searchWeb performs the fallback HTML search only after the API already failed (apiErr); when client.Do also fails, the returned error combines both: the web-request error via %v and the original API error for context. It means both the JSON API and the HTML scraping path were unreachable.
Solutions
- Check connectivity/DNS to both the API and web hosts
- Update API/web base URL constants after any site domain migration
- Configure an HTTP proxy for blocked upstreams
- Read both %v causes: the web error and the original apiErr
Example fix
// before
resp, err := client.Do(req)
if err != nil {
return nil, fmt.Errorf("[%s] API 失败且网页搜索请求失败: %v (API: %v)", p.Name(), err, apiErr)
}
// after
resp, err := client.Do(req)
if err != nil {
return nil, fmt.Errorf("[%s] API 失败且网页搜索请求失败: %w (API: %v)", p.Name(), err, apiErr)
} Defensive patterns
Strategy: fallback
Validate before calling
// reachability pre-check across both endpoints
for _, host := range []string{apiBaseHost, webBaseHost} {
if _, err := net.LookupHost(host); err != nil {
log.Printf("host unreachable, skipping plugin: %s", host)
}
} Try / catch
results, err := plugin.Search(keyword)
if err != nil && strings.Contains(err.Error(), "API 失败且网页搜索请求失败") {
log.Printf("both feikuai paths failed: %v", err)
results = queryAlternativePlugins(keyword) // multi-source aggregation
} Prevention
- Aggregate multiple search plugins so total failure of one is non-fatal
- Monitor DNS resolution of both hosts; automate domain-constant updates
- Route through a proxy when the site is geo-blocked
- Keep the error's dual causes (web + API) in logs for diagnosis
When it happens
Trigger: client.Do(req) in searchWeb returns non-nil while searchWeb was entered because searchImpl's API request had already failed (apiErr non-nil).
Common situations: Entire site blocked/DNS-poisoned from this host, site domain rotated (feikuai.tv -> feikuai.in) leaving both URLs stale, network outage or missing proxy for geo-blocked content.
Related errors
AI-assisted analysis of fish2018/pansou@beaa561337 (2026-09-07).
Data as JSON: /api/errors/84fde401125e0886.
Report an issue: GitHub.
Appendix: source
Thrown at plugin/feikuai/feikuai.go:185
// searchWebFallback parses the current server-rendered external search page.
// Feikuai's legacy JSON endpoint now responds with 403, while this page still
// exposes both disk links and magnets in stable HTML markup.
func (p *FeikuaiPlugin) searchWeb(client *http.Client, keyword string, apiErr error) ([]model.SearchResult, error) {
ctx, cancel := context.WithTimeout(context.Background(), DefaultTimeout)
defer cancel()
searchURL := SearchWebURL + "?wd=" + url.QueryEscape(keyword) + "&ext=1"
req, err := http.NewRequestWithContext(ctx, http.MethodGet, 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 Chrome/136.0.0.0 Safari/537.36")
req.Header.Set("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8")
req.Header.Set("Accept-Language", "zh-CN,zh;q=0.9,en;q=0.8")
req.Header.Set("Referer", "https://feikuai.in/")
resp, err := client.Do(req)
if err != nil {
return nil, fmt.Errorf("[%s] API 失败且网页搜索请求失败: %v (API: %v)", p.Name(), err, apiErr)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("[%s] API 失败且网页搜索返回状态码 %d (API: %v)", p.Name(), resp.StatusCode, apiErr)
}
doc, err := goquery.NewDocumentFromReader(resp.Body)
if err != nil {
return nil, fmt.Errorf("[%s] 网页搜索 HTML 解析失败: %w", p.Name(), err)
}
results := make([]model.SearchResult, 0, 64)
seen := make(map[string]struct{})
add := func(linkURL, title, content string, datetime time.Time) {
linkURL = strings.TrimSpace(linkURL)
if linkURL == "" {
return
}
linkType := util.GetLinkType(linkURL)View on GitHub (pinned to beaa561337)