{"record":{"id":"23febc88cfdf1dc9","repo":"fish2018/pansou","slug":"http-d-23febc","errorCode":null,"errorMessage":"HTTP %d","messagePattern":"HTTP %d","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"plugin/gying/gying.go","lineNumber":2725,"sourceCode":"\t}\n\n\tif DebugLog {\n\t\tfmt.Printf(\"[Gying]     响应状态码: %d\\n\", statusCode)\n\t}\n\n\t// 检查403错误\n\tif statusCode == http.StatusForbidden {\n\t\tif DebugLog {\n\t\t\tfmt.Printf(\"[Gying]     ❌ 详情接口返回403 - Cookie可能已过期\\n\")\n\t\t}\n\t\treturn nil, fmt.Errorf(\"HTTP 403 Forbidden\")\n\t}\n\n\tif statusCode != http.StatusOK {\n\t\tif DebugLog {\n\t\t\tfmt.Printf(\"[Gying]     ❌ HTTP错误: %d\\n\", statusCode)\n\t\t}\n\t\treturn nil, fmt.Errorf(\"HTTP %d\", statusCode)\n\t}\n\n\tif DebugLog {\n\t\tfmt.Printf(\"[Gying]     响应长度: %d 字节\\n\", len(body))\n\t}\n\tif isLoginShell(body) {\n\t\treturn nil, fmt.Errorf(\"HTTP 403 Forbidden\")\n\t}\n\n\tvar detail DetailData\n\tif err := json.Unmarshal(body, &detail); err != nil {\n\t\tif DebugLog {\n\t\t\tfmt.Printf(\"[Gying]     JSON解析失败: %v\\n\", err)\n\t\t\t// 打印前200字符\n\t\t\tpreview := string(body)\n\t\t\tif len(preview) > 200 {\n\t\t\t\tpreview = preview[:200] + \"...\"\n\t\t\t}","sourceCodeStart":2707,"sourceCodeEnd":2743,"githubUrl":"https://github.com/fish2018/pansou/blob/beaa56133755a548ebc51b090b3816e2ae044aa6/plugin/gying/gying.go#L2707-L2743","documentation":"fetchDetail throws this generic status-code error when the detail endpoint returns any non-200, non-403 HTTP status (e.g. 404, 429, 500, 502). It signals an unexpected server-side or routing failure rather than a session problem; the plugin deliberately does not parse the body in this branch.","triggerScenarios":"Calling fetchDetail while the site returns a status other than 200/403: resource deleted (404), rate limiting (429), upstream maintenance (5xx), or redirects followed to an error page.","commonSituations":"Site under maintenance or temporarily down; too many concurrent detail fetches triggering 429; resource ID/type from stale search results that no longer exist; CDN misbehaving.","solutions":["Check DebugLog output for the printed status code to identify the class of failure.","Retry with backoff for transient 429/5xx statuses.","If 404, refresh search results to obtain a valid resource ID/type.","Check the site's availability in a browser; if down, wait and retry later."],"exampleFix":"// before\nbody, statusCode, _, err := p.requestWithChallengeRetry(scraper, http.MethodGet, detailURL, \"\", \"\")\n// after\nbody, statusCode, _, err := p.requestWithChallengeRetry(scraper, http.MethodGet, detailURL, \"\", \"\")\nif err == nil && statusCode == http.StatusTooManyRequests {\n    time.Sleep(retryBackoff)\n    body, statusCode, _, err = p.requestWithChallengeRetry(scraper, http.MethodGet, detailURL, \"\", \"\")\n}","handlingStrategy":"retry","validationCode":"// preflight availability check\nresp, err := http.Head(siteBaseURL)\nif err != nil || resp.StatusCode >= 500 { return errors.New(\"site unavailable\") }","typeGuard":"func isRetryableStatus(err error) bool {\n  if err == nil { return false }\n  var code int\n  if _, e := fmt.Sscanf(err.Error(), \"HTTP %d\", &code); e != nil { return false }\n  return code == 429 || code >= 500\n}","tryCatchPattern":"detail, err := plugin.fetchDetail(id, typ, scraper)\nif isRetryableStatus(err) {\n    time.Sleep(5 * time.Second)\n    detail, err = plugin.fetchDetail(id, typ, scraper)\n}","preventionTips":["Implement exponential backoff for 429 and 5xx statuses.","Check site availability/maintenance before large batch runs.","Refresh search results instead of reusing old resource IDs.","Cap concurrency so the site does not throttle you."],"tags":["http","network","status-code"],"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"}