{"record":{"id":"a1083c50e86f86f7","repo":"fish2018/pansou","slug":"s-d-a1083c","errorCode":null,"errorMessage":"[%s] 请求返回状态码: %d","messagePattern":"\\[(.+?)\\] 请求返回状态码: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"plugin/clmao/clmao.go","lineNumber":194,"sourceCode":"\t// 创建请求\n\treq, err := http.NewRequestWithContext(ctx, \"GET\", searchURL, nil)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"[%s] 创建请求失败: %w\", p.Name(), err)\n\t}\n\n\t// 设置请求头\n\tp.setRequestHeaders(req)\n\n\t// 发送HTTP请求\n\tresp, err := p.doRequestWithRetry(req, client)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"[%s] 搜索请求失败: %w\", p.Name(), err)\n\t}\n\tdefer resp.Body.Close()\n\n\t// 检查状态码\n\tif resp.StatusCode != 200 {\n\t\treturn nil, fmt.Errorf(\"[%s] 请求返回状态码: %d\", p.Name(), resp.StatusCode)\n\t}\n\n\t// 读取响应体内容\n\tbody, err := io.ReadAll(resp.Body)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"[%s] 读取响应失败: %w\", p.Name(), err)\n\t}\n\n\tdecodedHTML := decodeModernPayload(string(body))\n\tif decodedHTML != string(body) {\n\t\tif modernResults := p.parseModernSearchResults(client, decodedHTML); len(modernResults) > 0 {\n\t\t\treturn modernResults, nil\n\t\t}\n\t}\n\n\t// 兼容旧模板\n\tdoc, err := goquery.NewDocumentFromReader(strings.NewReader(decodedHTML))\n\tif err != nil {","sourceCodeStart":176,"sourceCodeEnd":212,"githubUrl":"https://github.com/fish2018/pansou/blob/beaa56133755a548ebc51b090b3816e2ae044aa6/plugin/clmao/clmao.go#L176-L212","documentation":"ClmaoPlugin.searchPage received an HTTP response whose status code is not 200 and turns it into an error that includes the actual code. The retry helper doRequestWithRetry only retries transport errors, so a non-200 (403 Forbidden, 429 Too Many Requests, 503, 404) reaches this check on the first attempt and fails immediately — these statuses are not retried.","triggerScenarios":"p.doRequestWithRetry returns a valid *http.Response whose resp.StatusCode != 200 — e.g. 403 from missing/expired cookies, 429 after too-frequent searches, or 503 during maintenance — and searchPage returns \"[clmao] 请求返回状态码: %d\".","commonSituations":"Anti-bot protection flagging the default User-Agent; running many searches in a short window and hitting rate limits; the site changed its URL structure so the old search path now 404s; the site is temporarily under maintenance (503).","solutions":["Log the status code and a response-body snippet to identify whether it's 403 (blocked), 429 (rate limited), or 404/5xx.","For 403: refresh/update cookies and User-Agent in setRequestHeaders to match a real browser.","For 429: back off and slow down request frequency; respect Retry-After header.","For 404: check whether the site changed its search endpoint and update searchURL.","Optionally extend doRequestWithRetry to retry on 429/5xx with backoff."],"exampleFix":"// before\nif resp.StatusCode != 200 {\n    return nil, fmt.Errorf(\"[%s] 请求返回状态码: %d\", p.Name(), resp.StatusCode)\n}\n// after\nif resp.StatusCode == http.StatusTooManyRequests {\n    if ra := resp.Header.Get(\"Retry-After\"); ra != \"\" {\n        if secs, e := strconv.Atoi(ra); e == nil { time.Sleep(time.Duration(secs) * time.Second) }\n    }\n    return nil, fmt.Errorf(\"[%s] rate limited (429)\", p.Name())\n}\nif resp.StatusCode != 200 {\n    return nil, fmt.Errorf(\"[%s] 请求返回状态码: %d\", p.Name(), resp.StatusCode)\n}","handlingStrategy":"fallback","validationCode":"// pre-flight status probe\nfunc statusOK(client *http.Client, url string) (bool, int) {\n    resp, err := client.Get(url)\n    if err != nil { return false, 0 }\n    defer resp.Body.Close()\n    return resp.StatusCode == http.StatusOK, resp.StatusCode\n}","typeGuard":null,"tryCatchPattern":"results, err := p.searchPage(client, keyword, page)\nif err != nil {\n    if strings.Contains(err.Error(), \"429\") {\n        time.Sleep(rateLimitBackoff) // retry later\n    } else if strings.Contains(err.Error(), \"403\") {\n        refreshSessionCookies()\n    }\n    return nil, err\n}","preventionTips":["Rotate/refresh User-Agent and cookies to avoid 403 blocks.","Rate-limit your search volume to avoid 429s.","Alert on recurring non-200 codes — they usually mean site changes or blocks.","Consider adding 429/5xx handling into the plugin's retry loop."],"tags":["http","status-code","anti-bot","rate-limit"],"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"}