{"record":{"id":"e9b15064c8f11ca4","repo":"fish2018/pansou","slug":"s-hsid-s-w-e9b150","errorCode":null,"errorMessage":"[%s] hsid=%s读取响应失败: %w","messagePattern":"\\[(.+?)\\] hsid=(.+?)读取响应失败: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"plugin/haisou/haisou.go","lineNumber":415,"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 \"\", \"\", fmt.Errorf(\"[%s] hsid=%s链接请求失败: %w\", p.Name(), hsid, err)\n\t}\n\tdefer resp.Body.Close()\n\n\t// 检查状态码\n\tif resp.StatusCode != 200 {\n\t\treturn \"\", \"\", fmt.Errorf(\"[%s] hsid=%s链接请求返回状态码: %d\", p.Name(), hsid, resp.StatusCode)\n\t}\n\n\t// 读取响应体\n\tbody, err := io.ReadAll(resp.Body)\n\tif err != nil {\n\t\treturn \"\", \"\", fmt.Errorf(\"[%s] hsid=%s读取响应失败: %w\", p.Name(), hsid, err)\n\t}\n\n\t// 解析响应\n\tvar apiResp FetchAPIResponse\n\tif err := json.Unmarshal(body, &apiResp); err != nil {\n\t\treturn \"\", \"\", fmt.Errorf(\"[%s] hsid=%s链接JSON解析失败: %w\", p.Name(), hsid, err)\n\t}\n\n\t// 检查API响应状态\n\tif apiResp.Code != 0 {\n\t\treturn \"\", \"\", fmt.Errorf(\"[%s] hsid=%s链接API错误: %s\", p.Name(), hsid, apiResp.Msg)\n\t}\n\n\t// 根据平台类型构建完整的分享链接\n\tshareURL := buildShareURL(platform, apiResp.Data.ShareCode)\n\tif shareURL == \"\" {\n\t\treturn \"\", \"\", fmt.Errorf(\"[%s] hsid=%s不支持的网盘平台: %s\", p.Name(), hsid, platform)\n\t}","sourceCodeStart":397,"sourceCodeEnd":433,"githubUrl":"https://github.com/fish2018/pansou/blob/beaa56133755a548ebc51b090b3816e2ae044aa6/plugin/haisou/haisou.go#L397-L433","documentation":"This error is thrown by fetchShareLink when the body of the (HTTP 200) share-link response cannot be read via io.ReadAll, e.g. the connection was closed mid-body or a decompression error occurred. It wraps the underlying read error with the plugin name and hsid.","triggerScenarios":"io.ReadAll(resp.Body) returns an error inside fetchShareLink — network interruption or connection reset while reading the response body.","commonSituations":"Flaky mobile/proxied networks dropping connections mid-transfer; server closing keep-alive connections early; responses with broken gzip/deflate encoding; LB idle timeouts.","solutions":["Retry the whole fetchShareLink call — the error is usually transient","Check proxy/LB idle timeout settings vs server response time","Verify any forced compression/decompression (Transport.DisableCompression) configuration","Increase maxRetries in doRequestWithRetry for flaky networks"],"exampleFix":"// before\nbody, err := io.ReadAll(resp.Body)\nif err != nil {\n\treturn \"\", \"\", fmt.Errorf(\"[%s] hsid=%s读取响应失败: %w\", p.Name(), hsid, err)\n}\n// after\nbody, err := io.ReadAll(io.LimitReader(resp.Body, 1<<20))\nif err != nil {\n\treturn \"\", \"\", fmt.Errorf(\"[%s] hsid=%s读取响应失败: %w\", p.Name(), hsid, err)\n}\nif len(body) == 0 {\n\treturn \"\", \"\", fmt.Errorf(\"[%s] hsid=%s响应体为空\", p.Name(), hsid)\n}","handlingStrategy":"retry","validationCode":"// nothing to validate pre-call; transient I/O error\n// defend by limiting read size and checking for empty bodies afterward","typeGuard":null,"tryCatchPattern":"body, err := io.ReadAll(io.LimitReader(resp.Body, 1<<20))\nif err != nil {\n\treturn fmt.Errorf(\"read share-link response failed: %w\", err)\n}","preventionTips":["Retry the whole request — mid-body failures are usually transient","Check LB/proxy idle timeouts against upstream latency","Cap body reads with io.LimitReader to avoid pathological responses","Monitor error rates to detect persistent network degradation"],"tags":["io","network","http","go"],"backgroundTag":"file-read-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"}