{"record":{"id":"387972cfae374c8a","repo":"fish2018/pansou","slug":"d-387972","errorCode":null,"errorMessage":"详情页请求返回状态码: %d","messagePattern":"详情页请求返回状态码: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"plugin/pianku/pianku.go","lineNumber":399,"sourceCode":"\t// 创建请求\n\treq, err := http.NewRequestWithContext(ctx, \"GET\", detailURL, nil)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"创建详情页请求失败: %w\", err)\n\t}\n\t\n\t// 设置请求头\n\tp.setRequestHeaders(req)\n\t\n\t// 发送HTTP请求\n\tresp, err := p.doRequestWithRetry(req, client)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"详情页请求失败: %w\", err)\n\t}\n\tdefer resp.Body.Close()\n\t\n\t// 检查状态码\n\tif resp.StatusCode != 200 {\n\t\treturn nil, fmt.Errorf(\"详情页请求返回状态码: %d\", resp.StatusCode)\n\t}\n\t\n\t// 解析HTML\n\tdoc, err := goquery.NewDocumentFromReader(resp.Body)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"详情页HTML解析失败: %w\", err)\n\t}\n\t\n\t// 提取下载链接\n\treturn p.extractDownloadLinks(doc), nil\n}\n\n// extractDownloadLinks 提取详情页中的下载链接\nfunc (p *PiankuPlugin) extractDownloadLinks(doc *goquery.Document) []model.Link {\n\tvar links []model.Link\n\tseenURLs := make(map[string]bool) // 用于去重\n\t\n\t// 查找下载链接区域","sourceCodeStart":381,"sourceCodeEnd":417,"githubUrl":"https://github.com/fish2018/pansou/blob/beaa56133755a548ebc51b090b3816e2ae044aa6/plugin/pianku/pianku.go#L381-L417","documentation":"Status error in pianku's fetchDetailPageLinks (plugin/pianku/pianku.go:399): a result's detail page returned a non-200 status. The search listing succeeded but this specific detail fetch was rejected (rate limit or removed page).","triggerScenarios":"p.doRequestWithRetry succeeded (transport OK) but resp.StatusCode != 200 — e.g. 403/429 from anti-bot, 404 from a dead link, or 5xx from the site while searchImpl was processing detail pages.","commonSituations":"详情页防盗链触发；帖子已删除。","solutions":["Log the failing URL and status; on 404 treat the detail page as gone and skip it.","Add exponential backoff between detail-page requests and honor Retry-After on 429/503 to avoid rate limiting.","Send realistic browser headers (setRequestHeaders) including a current User-Agent and Referer to bypass simple bot checks.","For 403 with Cloudflare, consider a cookie/session bootstrap or reduce request concurrency."],"exampleFix":"// before\nif resp.StatusCode != 200 {\n    return nil, fmt.Errorf(\"详情页请求返回状态码: %d\", resp.StatusCode)\n}\n// after\nif resp.StatusCode == http.StatusNotFound {\n    return nil, nil // dead link, skip\n}\nif resp.StatusCode != 200 {\n    return nil, fmt.Errorf(\"详情页请求返回状态码: %d (url=%s)\", resp.StatusCode, detailURL)\n}","handlingStrategy":"try-catch","validationCode":"// probe the URL before extraction and treat 4xx as expected\nresp, err := client.Head(detailURL)\nif err == nil && (resp.StatusCode == 404 || resp.StatusCode == 410) {\n    return // dead link, skip\n}","typeGuard":"func isNotFoundStatus(err error) bool {\n    return err != nil && strings.Contains(err.Error(), \"状态码: 404\")\n}","tryCatchPattern":"results, err := plugin.Search(keyword)\nif err != nil && strings.Contains(err.Error(), \"详情页请求返回状态码\") {\n    if strings.Contains(err.Error(), \": 429\") {\n        time.Sleep(30 * time.Second) // honor rate limit then retry\n    } else {\n        return fallbackResults, nil\n    }\n}","preventionTips":["Throttle detail-page requests to avoid 429 rate limiting.","Keep User-Agent/Referer headers current to avoid 403 bot checks.","Expect and handle 404 for stale links — sites remove pages.","Honor Retry-After headers on 429/503 responses."],"tags":["http","status-code","scraping","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"}