{"record":{"id":"4d5c81e1a3bd5cc3","repo":"fish2018/pansou","slug":"s-d-4d5c81","errorCode":null,"errorMessage":"[%s] 请求返回状态码: %d","messagePattern":"\\[(.+?)\\] 请求返回状态码: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"plugin/cldi/cldi.go","lineNumber":151,"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// 发送请求\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\t// 解析HTML\n\tdoc, err := goquery.NewDocumentFromReader(strings.NewReader(string(body)))\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"[%s] HTML解析失败: %w\", p.Name(), err)\n\t}\n\n\t// 提取搜索结果\n\treturn p.extractSearchResults(doc), nil\n}\n","sourceCodeStart":133,"sourceCodeEnd":169,"githubUrl":"https://github.com/fish2018/pansou/blob/beaa56133755a548ebc51b090b3816e2ae044aa6/plugin/cldi/cldi.go#L133-L169","documentation":"CldiPlugin.searchPage returns this when the search endpoint responds with a status code other than 200. It reports the plugin name and the actual code but discards the response body, so the reason (block page, rate-limit notice, server error) is not visible. It indicates an upstream/API-level rejection rather than a transport failure.","triggerScenarios":"resp.StatusCode != 200 after doRequestWithRetry succeeds in searchPage — e.g. 403 from anti-bot WAF, 429 rate limit, 503 maintenance, or a changed endpoint returning 404.","commonSituations":"Scraping too aggressively triggering rate limits, IP banned by the site, site redesign moving the endpoint, or missing/rotated cookies and User-Agent headers.","solutions":["Read and log a snippet of resp.Body before returning so the actual rejection reason is visible.","If 429, reduce request rate or honor Retry-After; add backoff in doRequestWithRetry.","If 403, refresh headers (User-Agent, Referer, cookies) via setRequestHeaders to mimic a real browser.","Confirm the endpoint path is still valid on the live site."],"exampleFix":"// before\nif resp.StatusCode != 200 {\n    return nil, fmt.Errorf(\"[%s] 请求返回状态码: %d\", p.Name(), resp.StatusCode)\n}\n// after\nif resp.StatusCode != 200 {\n    snippet, _ := io.ReadAll(io.LimitReader(resp.Body, 512))\n    return nil, fmt.Errorf(\"[%s] 请求返回状态码: %d, body: %s\", p.Name(), resp.StatusCode, snippet)\n}","handlingStrategy":"fallback","validationCode":null,"typeGuard":null,"tryCatchPattern":"results, err := plugin.Search(ctx, keyword)\nif err != nil {\n    if m := regexp.MustCompile(`状态码: (\\d+)`).FindStringSubmatch(err.Error()); m != nil {\n        switch m[1] {\n        case \"429\":\n            // back off / slow down request rate\n        case \"403\", \"404\":\n            // endpoint blocked or moved: switch to fallback source\n        }\n    }\n}","preventionTips":["Throttle scraping to stay under rate limits","Rotate realistic browser headers and cookies","Alert on persistent non-200s so endpoint changes are caught quickly","Capture the response body on non-200 to enable diagnosis"],"tags":["http","status-code","scraping","plugin"],"backgroundTag":"http-error-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"}