{"record":{"id":"664b94d59ec0fc62","repo":"fish2018/pansou","slug":"d-v","errorCode":null,"errorMessage":"请求失败，状态码: %d，且读取响应体错误: %v","messagePattern":"请求失败，状态码: (.+?)，且读取响应体错误: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"plugin/panyq/panyq.go","lineNumber":671,"sourceCode":"\t\n\t// 只保留指定的请求头\n\t// req.Header.Set(\"sec-ch-ua\", `\"Not)A;Brand\";v=\"8\", \"Chromium\";v=\"138\", \"Google Chrome\";v=\"138\"`)\n\treq.Header.Set(\"User-Agent\", \"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36\")\n\t\n\t// 发送请求\n\tresp, err := client.Do(req)\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 != http.StatusOK {\n\t\t// 读取响应体以获取服务器返回的具体错误信息\n\t\tbodyBytes, err := io.ReadAll(resp.Body)\n\t\tif err != nil {\n\t\t\t// 如果连响应体都读取失败，则返回状态码错误并附上读取错误\n\t\t\treturn nil, fmt.Errorf(\"请求失败，状态码: %d，且读取响应体错误: %v\", resp.StatusCode, err)\n\t\t}\n\t\t// 将更详细的状态信息 (如 \"404 Not Found\") 和响应体内容一起作为错误返回\n\t\treturn nil, fmt.Errorf(\"请求失败，状态: %s, 详情: %s\", resp.Status, string(bodyBytes))\n\t}\n\n\tbody, err := io.ReadAll(resp.Body)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"读取响应失败: %w\", err)\n\t}\n\t\n\t// 提取JS文件路径\n\tjsRegex := regexp.MustCompile(`<script src=\"(/_next/static/[^\"]+\\.js)\"`)\n\tmatches := jsRegex.FindAllStringSubmatch(string(body), -1)\n\t\n\tif len(matches) == 0 {\n\t\treturn nil, fmt.Errorf(\"未找到JS文件\")\n\t}\n\t","sourceCodeStart":653,"sourceCodeEnd":689,"githubUrl":"https://github.com/fish2018/pansou/blob/beaa56133755a548ebc51b090b3816e2ae044aa6/plugin/panyq/panyq.go#L653-L689","documentation":"When the homepage responds with a non-200 status code, the function reads the response body to include the server's error details. If even reading that body fails (connection reset mid-read, context canceled, body already consumed), it returns this combined message: the numeric status code plus the body-read error. It signals both a failed request outcome and a degraded ability to diagnose it.","triggerScenarios":"Server returned e.g. 403/429/502 from findPotentialActionIDs' homepage request AND io.ReadAll(resp.Body) errored — typically because the server closed the connection immediately after sending headers, or the request context deadline expired during the read.","commonSituations":"Anti-bot/WAF (e.g. Cloudflare) returns 403 and immediately resets the connection; rate limiter closes the socket; server sends Content-Length but truncates the body; client timeout set shorter than server response time.","solutions":["Retry with backoff — connection resets on non-200 responses are usually transient or rate-limit related.","Check for rate limiting (429) or blocking (403) and slow down / rotate the User-Agent or IP.","Increase the HTTP client timeout so the body read can complete.","Add http.NoBody / status-only fallback: log the status code even when the body cannot be read, so diagnosis doesn't depend on the body.","Verify the User-Agent/header set is not triggering immediate connection drops from the WAF."],"exampleFix":"// before\nreturn nil, fmt.Errorf(\"请求失败，状态码: %d，且读取响应体错误: %v\", resp.StatusCode, err)\n// after\nif resp.StatusCode == http.StatusTooManyRequests {\n    return nil, fmt.Errorf(\"请求被限流(429)，请降低频率: 读取响应体错误: %v\", err)\n}\nreturn nil, fmt.Errorf(\"请求失败，状态码: %d，且读取响应体错误: %w\", resp.StatusCode, err)","handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"_, err := discoverActionIDs(ctx)\nif err != nil {\n    var httpErr *HTTPStatusError\n    if errors.As(err, &httpErr) && isRetryable(httpErr.StatusCode) {\n        return retryWithBackoff(ctx)\n    }\n    return err\n}","preventionTips":["Throttle calls to discoverActionIDs to avoid 429-driven connection drops.","Send complete browser-like headers to reduce WAF resets.","Set client timeout longer than worst-case response time.","Log the status code independently of the body so failures stay diagnosable."],"tags":["http","network","scraping","go"],"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"}