{"record":{"id":"9468416ec6c2a21a","repo":"fish2018/pansou","slug":"s-d-946841","errorCode":null,"errorMessage":"[%s] 搜索返回状态码: %d","messagePattern":"\\[(.+?)\\] 搜索返回状态码: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"plugin/kkmao/kkmao.go","lineNumber":129,"sourceCode":"\tsearchURL := fmt.Sprintf(\"https://www.kuakemao.com/?s=%s\", url.QueryEscape(keyword))\n\tctx, cancel := context.WithTimeout(context.Background(), searchTimeout)\n\tdefer cancel()\n\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\n\tsetCommonHeaders(req, \"https://www.kuakemao.com/\")\n\n\tresp, err := p.doRequestWithRetry(req, client, searchMaxRetries, retryBaseDelay)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"[%s] 搜索请求失败: %w\", p.Name(), err)\n\t}\n\tdefer resp.Body.Close()\n\n\tif resp.StatusCode != http.StatusOK {\n\t\treturn nil, fmt.Errorf(\"[%s] 搜索返回状态码: %d\", p.Name(), resp.StatusCode)\n\t}\n\n\tdoc, err := goquery.NewDocumentFromReader(resp.Body)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"[%s] 解析搜索页面失败: %w\", p.Name(), err)\n\t}\n\n\tvar (\n\t\tresults []model.SearchResult\n\t\twg      sync.WaitGroup\n\t\tmu      sync.Mutex\n\t\tsem     = make(chan struct{}, maxConcurrency)\n\t)\n\n\tdoc.Find(\"article.excerpt\").Each(func(_ int, item *goquery.Selection) {\n\t\ttitleSel := item.Find(\"header h2 a\")\n\t\ttitle := strings.TrimSpace(titleSel.Text())\n\t\tdetailURL, ok := titleSel.Attr(\"href\")","sourceCodeStart":111,"sourceCodeEnd":147,"githubUrl":"https://github.com/fish2018/pansou/blob/beaa56133755a548ebc51b090b3816e2ae044aa6/plugin/kkmao/kkmao.go#L111-L147","documentation":"Status error in KkMaoPlugin.searchImpl (plugin/kkmao/kkmao.go:129): the search page returned a status other than 200 after retry. The site was reachable but refused the request (rate limiting or anti-bot), so parsing is skipped.","triggerScenarios":"Any non-200 status: 403 (Cloudflare/WAF block), 404 (search route changed), 429 (too many requests), 5xx (server-side failure).","commonSituations":"高频搜索触发限流；站点临时维护。","solutions":["Log status plus a body snippet to distinguish blocking vs server error","Update setCommonHeaders to mimic a current browser (fresh User-Agent, cookies)","Throttle request rate to avoid 429; add jitter/backoff","Verify the search endpoint path is still correct in a browser"],"exampleFix":"// before\nif resp.StatusCode != http.StatusOK {\n    return nil, fmt.Errorf(\"[%s] 搜索返回状态码: %d\", p.Name(), resp.StatusCode)\n}\n// after\nif resp.StatusCode == http.StatusTooManyRequests {\n    time.Sleep(2 * time.Second)\n    return p.searchImpl(ctx, client, keyword) // or propagate retry signal\n}\nif resp.StatusCode != http.StatusOK {\n    return nil, fmt.Errorf(\"[%s] 搜索返回状态码: %d\", p.Name(), resp.StatusCode)\n}","handlingStrategy":"retry","validationCode":"resp, err := http.Head(\"https://www.kuakemao.com/?s=test\")\nif err == nil && resp.StatusCode != http.StatusOK {\n    return fmt.Errorf(\"kuakemao returning %d; fix headers/proxy before scraping\", resp.StatusCode)\n}","typeGuard":null,"tryCatchPattern":"results, err := plugin.Search(keyword)\nif err != nil {\n    if strings.Contains(err.Error(), \"搜索返回状态码\") {\n        return backoffAndRetry(err) // 429/403 often transient\n    }\n    return err\n}","preventionTips":["Rotate/refresh browser-like headers regularly","Throttle request rate; respect Retry-After on 429","Alert when status codes indicate permanent blocking","Verify search route still exists after site updates"],"tags":["go","http","status-code","plugin"],"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"}