{"record":{"id":"5371b3776a8fb254","repo":"fish2018/pansou","slug":"http-error-page-d-type-s-d","errorCode":null,"errorMessage":"HTTP error (page %d, type %s): %d","messagePattern":"HTTP error \\(page (.+?), type (.+?)\\): (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"plugin/sousou/sousou.go","lineNumber":426,"sourceCode":"\t\t\treq.Header.Set(\"Accept-Language\", \"zh-CN,zh;q=0.9,en;q=0.8\")\n\t\t\treq.Header.Set(\"Connection\", \"keep-alive\")\n\t\t\treq.Header.Set(\"Referer\", \"https://sousou.pro/\")\n\n\t\t\t// 发送请求\n\t\t\tresp, err := client.Do(req)\n\t\t\tif err != nil {\n\t\t\t\tdebugLog(\"请求失败 (page %d, type %s): %v\", pageNum, diskType, err)\n\t\t\t\terrChan <- fmt.Errorf(\"request failed (page %d, type %s): %w\", pageNum, diskType, err)\n\t\t\t\treturn\n\t\t\t}\n\t\t\tdefer resp.Body.Close()\n\n\t\t\tdebugLog(\"收到响应 (page %d, type %s), 状态码: %d\", pageNum, diskType, resp.StatusCode)\n\n\t\t\t// 检查状态码\n\t\t\tif resp.StatusCode != 200 {\n\t\t\t\tdebugLog(\"HTTP错误 (page %d, type %s): %d\", pageNum, diskType, resp.StatusCode)\n\t\t\t\terrChan <- fmt.Errorf(\"HTTP error (page %d, type %s): %d\", pageNum, diskType, resp.StatusCode)\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\t// 读取响应体\n\t\t\trespBody, err := io.ReadAll(resp.Body)\n\t\t\tif err != nil {\n\t\t\t\tdebugLog(\"读取响应失败 (page %d, type %s): %v\", pageNum, diskType, err)\n\t\t\t\terrChan <- fmt.Errorf(\"read response body failed (page %d, type %s): %w\", pageNum, diskType, err)\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tdebugLog(\"响应内容 (page %d, type %s, 前500字符): %s\", pageNum, diskType, string(respBody[:min(500, len(respBody))]))\n\n\t\t\t// 解析响应\n\t\t\tvar apiResp SousouResponse\n\t\t\tif err := json.Unmarshal(respBody, &apiResp); err != nil {\n\t\t\t\tdebugLog(\"JSON解析失败 (page %d, type %s): %v\", pageNum, diskType, err)\n\t\t\t\terrChan <- fmt.Errorf(\"decode response failed (page %d, type %s): %w\", pageNum, diskType, err)","sourceCodeStart":408,"sourceCodeEnd":444,"githubUrl":"https://github.com/fish2018/pansou/blob/beaa56133755a548ebc51b090b3816e2ae044aa6/plugin/sousou/sousou.go#L408-L444","documentation":"Per-page sentinel in sousou's concurrent fetch: the request for a given page/diskType succeeded at transport level but returned a status other than 200. Page number and disk type identify the exact failed shard; sent to errChan so one bad page does not kill the others.","triggerScenarios":"The sousou API endpoint returns 403 (anti-bot/Cloudflare), 429 (rate limited), 404 (endpoint changed), or 5xx for the given page/type request.","commonSituations":"Rapid fan-out of parallel page requests triggers rate limiting; the site puts a WAF/CDN challenge in front of the API; the API path changed after a site update.","solutions":["Retry after a delay on 429/5xx, respecting any Retry-After header","Add per-request jitter/delays and cap concurrency to avoid rate limits","Send browser-like headers (already sets UA/Accept; add Referer/Cookie if needed) to pass WAF checks","Log the response body on non-200 to see the WAF or API error detail"],"exampleFix":"// before\nif resp.StatusCode != 200 {\n    errChan <- fmt.Errorf(\"HTTP error (page %d, type %s): %d\", pageNum, diskType, resp.StatusCode)\n    return\n}\n// after\nif resp.StatusCode == http.StatusTooManyRequests {\n    errChan <- fmt.Errorf(\"rate limited (page %d, type %s), retry after %s\", pageNum, diskType, resp.Header.Get(\"Retry-After\"))\n    return\n}\nif resp.StatusCode != 200 {\n    errChan <- fmt.Errorf(\"HTTP error (page %d, type %s): %d\", pageNum, diskType, resp.StatusCode)\n    return\n}","handlingStrategy":"retry","validationCode":"// after client.Do\nif resp.StatusCode != 200 {\n    body, _ := io.ReadAll(io.LimitReader(resp.Body, 512))\n    return fmt.Errorf(\"status %d body=%.512s\", resp.StatusCode, body)\n}","typeGuard":"func retryableStatus(code int) bool { return code == 429 || code == 502 || code == 503 || code == 504 }","tryCatchPattern":"if err != nil {\n    var statusErr *StatusError\n    if errors.As(err, &statusErr) && retryableStatus(statusErr.Code) {\n        time.Sleep(backoff); goto retry\n    }\n}","preventionTips":["Limit concurrent worker goroutines and add jitter delays","Honor Retry-After headers on 429","Send Referer/Cookie headers to pass WAF checks","Log the body of non-200 responses to diagnose WAF vs API errors"],"tags":["http","status-code","rate-limit"],"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"}