{"record":{"id":"3c227978e453c92d","repo":"fish2018/pansou","slug":"s-s-d-w-3c2279","errorCode":null,"errorMessage":"[%s] %s网盘第%d页读取响应失败: %w","messagePattern":"\\[(.+?)\\] (.+?)网盘第(.+?)页读取响应失败: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"plugin/haisou/haisou.go","lineNumber":353,"sourceCode":"\treq.Header.Set(\"Connection\", \"keep-alive\")\n\treq.Header.Set(\"Referer\", \"https://haisou.cc/\")\n\n\t// 发送HTTP请求（带重试机制）\n\tresp, err := p.doRequestWithRetry(req, client)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"[%s] %s网盘第%d页请求失败: %w\", p.Name(), panType, pageNo, err)\n\t}\n\tdefer resp.Body.Close()\n\n\t// 检查状态码\n\tif resp.StatusCode != 200 {\n\t\treturn nil, fmt.Errorf(\"[%s] %s网盘第%d页返回状态码: %d\", p.Name(), panType, pageNo, 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] %s网盘第%d页读取响应失败: %w\", p.Name(), panType, pageNo, err)\n\t}\n\n\t// 解析响应\n\tvar apiResp SearchAPIResponse\n\tif err := json.Unmarshal(body, &apiResp); err != nil {\n\t\treturn nil, fmt.Errorf(\"[%s] %s网盘第%d页JSON解析失败: %w\", p.Name(), panType, pageNo, err)\n\t}\n\n\t// 检查API响应状态\n\tif apiResp.Code != 0 {\n\t\treturn nil, fmt.Errorf(\"[%s] %s网盘第%d页API错误: %s\", p.Name(), panType, pageNo, apiResp.Msg)\n\t}\n\n\tif DebugLog {\n\t\tfmt.Printf(\"[%s] %s网盘第%d页获取到 %d 个搜索结果\\n\", p.Name(), panType, pageNo, len(apiResp.Data.List))\n\t}\n\n\treturn apiResp.Data.List, nil","sourceCodeStart":335,"sourceCodeEnd":371,"githubUrl":"https://github.com/fish2018/pansou/blob/beaa56133755a548ebc51b090b3816e2ae044aa6/plugin/haisou/haisou.go#L335-L371","documentation":"fetchSearchPage reads the whole response body with io.ReadAll and wraps any read failure with this message naming the plugin, pan type, and page. This happens when the connection breaks mid-body — the server closed the connection early, a keep-alive socket died, or a proxy interrupted the transfer.","triggerScenarios":"Calling fetchSearchPage when io.ReadAll(resp.Body) errors: connection reset while streaming the body, server timeout mid-response, broken keep-alive connection reuse, or proxy truncating the response.","commonSituations":"Unstable network between the host and haisou.cc; server dropping long responses; HTTP client reusing a stale keep-alive connection; middlebox/proxy cutting idle or long connections.","solutions":["Retry the request — the failure is usually transient; the retry wrapper handles the send but not the body read, so add a read-level retry.","Disable keep-alive reuse (set req.Close = true or a fresh Transport) to avoid stale-connection read failures.","Check network stability/proxy health between the host and the site.","Set sensible limits with io.LimitReader if huge bodies are a concern."],"exampleFix":"// before\nbody, err := io.ReadAll(resp.Body)\nif err != nil {\n    return nil, fmt.Errorf(\"...读取响应失败: %w\", err)\n}\n// after\nbody, err := io.ReadAll(resp.Body)\nif err != nil {\n    time.Sleep(2 * time.Second)\n    return p.fetchSearchPage(panType, keyword, pageNo) // retry once on transient read failure\n}","handlingStrategy":"retry","validationCode":"// preflight connection stability\nif _, err := http.Get(\"https://haisou.cc/\"); err != nil {\n    return fmt.Errorf(\"unstable connection to upstream: %w\", err)\n}","typeGuard":"func isBodyReadError(err error) bool { return err != nil && strings.Contains(err.Error(), \"读取响应失败\") }","tryCatchPattern":"items, err := fetchSearchPage(panType, keyword, pageNo)\nif isBodyReadError(err) {\n    time.Sleep(2 * time.Second)\n    items, err = fetchSearchPage(panType, keyword, pageNo)\n}","preventionTips":["Retry at the page level on transient read failures.","Avoid stale keep-alive connections (short IdleConnTimeout or per-request connections).","Use stable network egress; check proxies/firewalls that cut long responses.","Keep timeouts aligned so the server isn't cut off mid-body."],"tags":["network","http","io","connection-reset"],"backgroundTag":"network-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"}