{"record":{"id":"7c3d3eb2866c1e56","repo":"fish2018/pansou","slug":"s-d-7c3d3e","errorCode":null,"errorMessage":"[%s] 请求返回状态码: %d","messagePattern":"\\[(.+?)\\] 请求返回状态码: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"plugin/jutoushe/jutoushe.go","lineNumber":76,"sourceCode":"\t}\n\n\t// 4. 设置请求头，避免反爬虫检测\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(\"Referer\", baseURL+\"/\")\n\n\t// 5. 发送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// 6. 检查状态码\n\tif resp.StatusCode != 200 {\n\t\treturn nil, fmt.Errorf(\"[%s] 请求返回状态码: %d\", p.Name(), resp.StatusCode)\n\t}\n\n\t// 7. 解析搜索结果页面\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\t// 8. 提取搜索结果\n\tvar results []model.SearchResult\n\tdoc.Find(\"ul.erx-list li.item\").Each(func(i int, s *goquery.Selection) {\n\t\t// 提取标题和链接\n\t\tlinkElem := s.Find(\".a a.main\")\n\t\ttitle := strings.TrimSpace(linkElem.Text())\n\t\tdetailPath, exists := linkElem.Attr(\"href\")\n\t\t\n\t\tif !exists || title == \"\" {\n\t\t\treturn // 跳过无效项","sourceCodeStart":58,"sourceCodeEnd":94,"githubUrl":"https://github.com/fish2018/pansou/blob/beaa56133755a548ebc51b090b3816e2ae044aa6/plugin/jutoushe/jutoushe.go#L58-L94","documentation":"jutoushe searchImpl returns this when the HTTP response status code is anything other than 200 after a successful request. It indicates the site responded but rejected the scrape attempt (or the page moved). No body inspection is done before failing.","triggerScenarios":"Any non-200 status from the search endpoint: 403 (bot blocking), 404 (page moved), 429 (rate limit), 5xx (server error).","commonSituations":"Site added WAF/anti-bot protection rejecting the fixed Chrome/91 User-Agent; search path changed; request throttled after frequent scraping.","solutions":["Log the actual status code and response body snippet to identify the cause","Refresh the User-Agent and other headers to a current browser value","Add backoff/rate-limiting between scrape requests to avoid 429/403","Handle redirects (check if 3xx and follow to the new URL structure)"],"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    body, _ := io.ReadAll(io.LimitReader(resp.Body, 512))\n    return nil, fmt.Errorf(\"[%s] 请求返回状态码: %d, body: %s\", p.Name(), resp.StatusCode, body)\n}","handlingStrategy":"retry","validationCode":"resp, err := http.Head(baseURL + \"/\")\nif err != nil || resp.StatusCode == http.StatusForbidden {\n    return errors.New(\"target site is blocking requests; adjust headers/proxy first\")\n}","typeGuard":null,"tryCatchPattern":"results, err := plugin.Search(keyword)\nif err != nil {\n    var statusErr interface{ Error() string }\n    if strings.Contains(err.Error(), \"请求返回状态码\") {\n        log.Printf(\"non-200 from source, backing off: %v\", err)\n        return backoffAndRetry(err)\n    }\n    return err\n}","preventionTips":["Keep browser headers (User-Agent, Accept) current","Rate-limit scraping to avoid 403/429","Log status codes and body snippets for diagnosis","Handle known redirect/changed routes explicitly"],"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"}