{"record":{"id":"ce0721d2630a367e","repo":"fish2018/pansou","slug":"s-w-ce0721","errorCode":null,"errorMessage":"[%s] 读取响应失败: %w","messagePattern":"\\[(.+?)\\] 读取响应失败: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"plugin/cldi/cldi.go","lineNumber":157,"sourceCode":"\t// 设置请求头\n\tp.setRequestHeaders(req)\n\n\t// 发送请求\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// 检查状态码\n\tif resp.StatusCode != 200 {\n\t\treturn nil, fmt.Errorf(\"[%s] 请求返回状态码: %d\", p.Name(), resp.StatusCode)\n\t}\n\n\t// 读取响应\n\tbody, err := io.ReadAll(resp.Body)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"[%s] 读取响应失败: %w\", p.Name(), err)\n\t}\n\n\t// 解析HTML\n\tdoc, err := goquery.NewDocumentFromReader(strings.NewReader(string(body)))\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"[%s] HTML解析失败: %w\", p.Name(), err)\n\t}\n\n\t// 提取搜索结果\n\treturn p.extractSearchResults(doc), nil\n}\n\n// setRequestHeaders 设置请求头\nfunc (p *CldiPlugin) setRequestHeaders(req *http.Request) {\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\")","sourceCodeStart":139,"sourceCodeEnd":175,"githubUrl":"https://github.com/fish2018/pansou/blob/beaa56133755a548ebc51b090b3816e2ae044aa6/plugin/cldi/cldi.go#L139-L175","documentation":"CldiPlugin.searchPage wraps io.ReadAll(resp.Body) failures with the plugin name. The response arrived but its body could not be read to completion — usually the connection was reset mid-transfer or the body was truncated (unexpected EOF). It is a one-shot read here: no retry is attempted after this point.","triggerScenarios":"io.ReadAll(resp.Body) returns err in searchPage, typically when the server or an intermediary closes the connection before the full HTML body is delivered.","commonSituations":"Large search-result pages over unstable connections, load balancer idle timeouts cutting the transfer, proxy interference, or server-side crashes mid-response.","solutions":["Retry the search; transient resets often succeed on a second attempt.","Check for intermediary proxies/LBs with short idle timeouts and raise them.","Increase client timeouts and use a bounded reader to avoid oversized bodies.","Verify network stability between client and the site."],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"results, err := plugin.Search(ctx, keyword)\nif err != nil {\n    if strings.Contains(err.Error(), \"读取响应失败\") {\n        // transient: retry once after short backoff, then degrade to cached results\n    }\n}","preventionTips":["Retry transient mid-body failures with backoff","Keep client timeouts comfortably above the site's p95 response time","Check intermediary proxy/LB timeouts that cut large transfers","Prefer a bounded reader with a sane max body size"],"tags":["io","http-body","network","plugin"],"backgroundTag":"http-request-failed","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"}