{"record":{"id":"9a52cf1b15d2b70d","repo":"fish2018/pansou","slug":"s-api-d-api-v","errorCode":null,"errorMessage":"[%s] API 失败且网页搜索返回状态码 %d (API: %v)","messagePattern":"\\[(.+?)\\] API 失败且网页搜索返回状态码 (.+?) \\(API: (.+?)\\)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"plugin/feikuai/feikuai.go","lineNumber":189,"sourceCode":"func (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)\n\t\tif linkType == \"\" || linkType == \"others\" {\n\t\t\treturn\n\t\t}\n\t\tif _, ok := seen[linkURL]; ok {","sourceCodeStart":171,"sourceCodeEnd":207,"githubUrl":"https://github.com/fish2018/pansou/blob/beaa56133755a548ebc51b090b3816e2ae044aa6/plugin/feikuai/feikuai.go#L171-L207","documentation":"In searchWeb, after the fallback HTML page loads, a non-200 status is reported with this message, which also embeds the original API failure (apiErr) since the web path only runs after the API path failed. It means the site answered but refused the scraping request.","triggerScenarios":"resp.StatusCode != http.StatusOK in searchWeb, typically 403 (anti-bot/WAF), 429 (rate limit), or 404/301 after a domain change, while the API path had already errored.","commonSituations":"Cloudflare or WAF challenge page for scraping requests, outdated Referer (https://feikuai.in/) after domain rotation, too-frequent scraping triggering throttling.","solutions":["Log the status code and check for HTML challenge pages in the body","Update User-Agent/Accept/Referer headers to match a current browser and the live domain","Add rate limiting or backoff between scraping requests","Update SearchWebURL when the site rotates domains"],"exampleFix":"// before\nif resp.StatusCode != http.StatusOK {\n    return nil, fmt.Errorf(\"[%s] API 失败且网页搜索返回状态码 %d (API: %v)\", p.Name(), resp.StatusCode, apiErr)\n}\n// after\nif resp.StatusCode != http.StatusOK {\n    return nil, fmt.Errorf(\"[%s] API 失败且网页搜索返回状态码 %d (API: %v)\", p.Name(), resp.StatusCode, apiErr)\n}\n// plus: refresh headers per live site, e.g.\nreq.Header.Set(\"Referer\", \"https://feikuai.in/\") // verify current domain","handlingStrategy":"retry","validationCode":"// slow the scrape rate to stay under throttling thresholds\nrateLimiter := rate.NewLimiter(rate.Every(500*time.Millisecond), 1)\n_ = rateLimiter.Wait(ctx) // before each search call","typeGuard":null,"tryCatchPattern":"results, err := plugin.Search(keyword)\nif err != nil && strings.Contains(err.Error(), \"网页搜索返回状态码\") {\n    if strings.Contains(err.Error(), \"429\") {\n        time.Sleep(10 * time.Second)\n        results, err = plugin.Search(keyword) // backoff retry\n    } else if strings.Contains(err.Error(), \"403\") {\n        log.Printf(\"feikuai WAF block; refresh headers or rotate proxy\")\n    }\n}","preventionTips":["Mirror the live site's browser headers including current Referer domain","Add per-request jitter and a global rate limit for scraping","Detect 403/429 early and back off instead of hammering","Track upstream domain rotations and update constants promptly"],"tags":["http","status-code","scraping"],"backgroundTag":"http-non-200-response","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"}