{"record":{"id":"d20fed98eeca5513","repo":"fish2018/pansou","slug":"s-d-d-d20fed","errorCode":null,"errorMessage":"[%s] 第%d页请求返回状态码: %d","messagePattern":"\\[(.+?)\\] 第(.+?)页请求返回状态码: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"plugin/thepiratebay/thepiratebay.go","lineNumber":272,"sourceCode":"\t// 5. 设置完整的请求头 - 参考插件开发指南的最佳实践\n\treq.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\")\n\treq.Header.Set(\"Accept\", \"text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8\")\n\treq.Header.Set(\"Accept-Language\", \"zh-CN,zh;q=0.9,en;q=0.8\")\n\treq.Header.Set(\"Connection\", \"keep-alive\")\n\treq.Header.Set(\"Upgrade-Insecure-Requests\", \"1\")\n\treq.Header.Set(\"Cache-Control\", \"max-age=0\")\n\treq.Header.Set(\"Referer\", \"https://thpibay.xyz/\")\n\t\n\t// 6. 发送HTTP请求（带重试机制）\n\tresp, err := p.doRequestWithRetry(req, client)\n\tif err != nil {\n\t\treturn nil, 0, fmt.Errorf(\"[%s] 第%d页搜索请求失败: %w\", p.Name(), page, err)\n\t}\n\tdefer resp.Body.Close()\n\t\n\t// 7. 检查状态码\n\tif resp.StatusCode != 200 {\n\t\treturn nil, 0, fmt.Errorf(\"[%s] 第%d页请求返回状态码: %d\", p.Name(), page, resp.StatusCode)\n\t}\n\t\n\t// 8. 解析HTML响应\n\tdoc, err := goquery.NewDocumentFromReader(resp.Body)\n\tif err != nil {\n\t\treturn nil, 0, fmt.Errorf(\"[%s] 第%d页HTML解析失败: %w\", p.Name(), page, err)\n\t}\n\t\n\t// 9. 解析分页信息（只在第一页解析）\n\ttotalPages := 1\n\tif page == 1 {\n\t\ttotalPages = p.parseTotalPages(doc)\n\t}\n\t\n\t// 10. 提取搜索结果\n\tresults := make([]model.SearchResult, 0)\n\tdoc.Find(\"table#searchResult tr\").Each(func(i int, s *goquery.Selection) {\n\t\t// 跳过表头","sourceCodeStart":254,"sourceCodeEnd":290,"githubUrl":"https://github.com/fish2018/pansou/blob/beaa56133755a548ebc51b090b3816e2ae044aa6/plugin/thepiratebay/thepiratebay.go#L254-L290","documentation":"searchPage requires HTTP 200 from the search endpoint. Any other status (403 bot-block, 404 gone mirror, 429 rate limit, 5xx server error) produces this error carrying the page number and status code. Unlike 723, the request succeeded at transport level — the server answered with a non-200 status.","triggerScenarios":"doRequestWithRetry returns a response whose StatusCode != 200 during a searchPage call: Cloudflare/anti-bot challenge page, mirror moved (404), too many rapid requests (429), or upstream outage (500/502/503).","commonSituations":"Mirror domain blocked/changed so requests hit a parking page; scraping too fast triggers rate limiting; missing/rotated User-Agent gets flagged by anti-bot; the .xyz mirror is dead.","solutions":["Log the response body snippet for the failing status to identify bot challenges vs dead pages.","Switch to a working mirror domain in the plugin configuration/constants.","Slow down request rate or add jitter between page fetches to avoid 429s.","Ensure realistic browser headers (User-Agent, Accept, Referer) are present — they already are; consider cookie handling for challenge pages.","Handle 5xx with the existing retry mechanism by treating retryable statuses in doRequestWithRetry."],"exampleFix":"// before\nif resp.StatusCode != 200 {\n    return nil, 0, fmt.Errorf(\"[%s] 第%d页请求返回状态码: %d\", p.Name(), page, resp.StatusCode)\n}\n// after: retry transient statuses\ncode := resp.StatusCode\nif code == 429 || code >= 500 {\n    io.Copy(io.Discard, resp.Body)\n    resp.Body.Close()\n    time.Sleep(2 * time.Second)\n    return p.searchPage(ctx, keyword, page) // bounded by caller\n}\nif code != 200 {\n    return nil, 0, fmt.Errorf(\"[%s] 第%d页请求返回状态码: %d\", p.Name(), page, code)\n}","handlingStrategy":"fallback","validationCode":"resp, err := http.Head(searchURL)\nif err == nil && resp.StatusCode != 200 {\n    return fmt.Errorf(\"mirror returned %d before searching, switch mirror\", resp.StatusCode)\n}","typeGuard":"func isRetryableStatus(code int) bool {\n    return code == 429 || code >= 500\n}\nfunc isBlockStatus(code int) bool {\n    return code == 403 || code == 503\n}","tryCatchPattern":"results, total, err := plugin.Search(keyword, page)\nvar statusErr error\nif err != nil && strings.Contains(err.Error(), \"请求返回状态码\") {\n    if strings.Contains(err.Error(), \": 403\") || strings.Contains(err.Error(), \": 503\") {\n        results, total, err = searchViaMirror(keyword, page) // bot-blocked: try alternate mirror/resolver\n    } else {\n        results, total, err = retryWithBackoff(2, func() ([]model.Item, int, error) {\n            return plugin.Search(keyword, page)\n        })\n    }\n}","preventionTips":["Keep a curated mirror list and probe it periodically.","Rate-limit requests with jitter so anti-bot/429 protections are not triggered.","Send full browser-like headers and reuse cookies across requests.","Log status + a small body snippet to distinguish blocking from outage."],"tags":["http","status-code","scraping","anti-bot"],"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"}