{"record":{"id":"84fde401125e0886","repo":"fish2018/pansou","slug":"s-api-v-api-v","errorCode":null,"errorMessage":"[%s] API 失败且网页搜索请求失败: %v (API: %v)","messagePattern":"\\[(.+?)\\] API 失败且网页搜索请求失败: (.+?) \\(API: (.+?)\\)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"plugin/feikuai/feikuai.go","lineNumber":185,"sourceCode":"\n// searchWebFallback parses the current server-rendered external search page.\n// Feikuai's legacy JSON endpoint now responds with 403, while this page still\n// exposes both disk links and magnets in stable HTML markup.\nfunc (p *FeikuaiPlugin) searchWeb(client *http.Client, keyword string, apiErr error) ([]model.SearchResult, error) {\n\tctx, cancel := context.WithTimeout(context.Background(), DefaultTimeout)\n\tdefer cancel()\n\tsearchURL := SearchWebURL + \"?wd=\" + url.QueryEscape(keyword) + \"&ext=1\"\n\treq, err := http.NewRequestWithContext(ctx, http.MethodGet, searchURL, nil)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"[%s] 创建网页搜索请求失败: %w\", p.Name(), err)\n\t}\n\treq.Header.Set(\"User-Agent\", \"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 Chrome/136.0.0.0 Safari/537.36\")\n\treq.Header.Set(\"Accept\", \"text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\")\n\treq.Header.Set(\"Accept-Language\", \"zh-CN,zh;q=0.9,en;q=0.8\")\n\treq.Header.Set(\"Referer\", \"https://feikuai.in/\")\n\tresp, err := client.Do(req)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"[%s] API 失败且网页搜索请求失败: %v (API: %v)\", p.Name(), err, apiErr)\n\t}\n\tdefer resp.Body.Close()\n\tif resp.StatusCode != http.StatusOK {\n\t\treturn nil, fmt.Errorf(\"[%s] API 失败且网页搜索返回状态码 %d (API: %v)\", p.Name(), resp.StatusCode, apiErr)\n\t}\n\tdoc, err := goquery.NewDocumentFromReader(resp.Body)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"[%s] 网页搜索 HTML 解析失败: %w\", p.Name(), err)\n\t}\n\n\tresults := make([]model.SearchResult, 0, 64)\n\tseen := make(map[string]struct{})\n\tadd := func(linkURL, title, content string, datetime time.Time) {\n\t\tlinkURL = strings.TrimSpace(linkURL)\n\t\tif linkURL == \"\" {\n\t\t\treturn\n\t\t}\n\t\tlinkType := util.GetLinkType(linkURL)","sourceCodeStart":167,"sourceCodeEnd":203,"githubUrl":"https://github.com/fish2018/pansou/blob/beaa56133755a548ebc51b090b3816e2ae044aa6/plugin/feikuai/feikuai.go#L167-L203","documentation":"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.","triggerScenarios":"client.Do(req) in searchWeb returns non-nil while searchWeb was entered because searchImpl's API request had already failed (apiErr non-nil).","commonSituations":"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.","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"],"exampleFix":"// before\nresp, err := client.Do(req)\nif err != nil {\n    return nil, fmt.Errorf(\"[%s] API 失败且网页搜索请求失败: %v (API: %v)\", p.Name(), err, apiErr)\n}\n// after\nresp, err := client.Do(req)\nif err != nil {\n    return nil, fmt.Errorf(\"[%s] API 失败且网页搜索请求失败: %w (API: %v)\", p.Name(), err, apiErr)\n}","handlingStrategy":"fallback","validationCode":"// reachability pre-check across both endpoints\nfor _, host := range []string{apiBaseHost, webBaseHost} {\n    if _, err := net.LookupHost(host); err != nil {\n        log.Printf(\"host unreachable, skipping plugin: %s\", host)\n    }\n}","typeGuard":null,"tryCatchPattern":"results, err := plugin.Search(keyword)\nif err != nil && strings.Contains(err.Error(), \"API 失败且网页搜索请求失败\") {\n    log.Printf(\"both feikuai paths failed: %v\", err)\n    results = queryAlternativePlugins(keyword) // multi-source aggregation\n}","preventionTips":["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"],"tags":["network","fallback-exhausted","http"],"backgroundTag":"network-request-failed","analyzedSha":"beaa56133755a548ebc51b090b3816e2ae044aa6","analyzedAt":"2026-09-07T00:31:18.025Z","contentChangedAt":"2026-09-07T00:31:18.025Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}