{"record":{"id":"08ea8235079f4d86","repo":"fish2018/pansou","slug":"s-w-08ea82","errorCode":null,"errorMessage":"[%s] 读取搜索响应失败: %w","messagePattern":"\\[(.+?)\\] 读取搜索响应失败: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"plugin/haitunsou/haitunsou.go","lineNumber":105,"sourceCode":"\tdefer cancel()\n\tsearchURL := fmt.Sprintf(\"%s/s/%s.html\", strings.TrimRight(p.baseURL, \"/\"), url.PathEscape(keyword))\n\treq, err := http.NewRequestWithContext(ctx, http.MethodGet, searchURL, nil)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"[%s] 创建搜索请求失败: %w\", p.Name(), err)\n\t}\n\tsetRequestHeaders(req, p.baseURL)\n\n\tresp, err := client.Do(req)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"[%s] 搜索请求失败: %w\", p.Name(), err)\n\t}\n\tdefer resp.Body.Close()\n\tif resp.StatusCode != http.StatusOK {\n\t\treturn nil, fmt.Errorf(\"[%s] 搜索请求返回 HTTP %d\", p.Name(), resp.StatusCode)\n\t}\n\tbody, err := io.ReadAll(io.LimitReader(resp.Body, maxResponseSize+1))\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"[%s] 读取搜索响应失败: %w\", p.Name(), err)\n\t}\n\tif len(body) > maxResponseSize {\n\t\treturn nil, fmt.Errorf(\"[%s] 搜索响应超过 %d 字节\", p.Name(), maxResponseSize)\n\t}\n\n\titems, err := parseEmbeddedList(body)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"[%s] 解析搜索结果失败: %w\", p.Name(), err)\n\t}\n\tresults := make([]model.SearchResult, 0, len(items))\n\tseen := make(map[string]struct{}, len(items))\n\tfor _, item := range items {\n\t\tresult, ok := convertItem(item)\n\t\tif !ok {\n\t\t\tcontinue\n\t\t}\n\t\tkey := result.Links[0].URL + \"\\x00\" + result.Links[0].Password\n\t\tif _, exists := seen[key]; exists {","sourceCodeStart":87,"sourceCodeEnd":123,"githubUrl":"https://github.com/fish2018/pansou/blob/beaa56133755a548ebc51b090b3816e2ae044aa6/plugin/haitunsou/haitunsou.go#L87-L123","documentation":"Returned by searchImpl when io.ReadAll fails while reading the (limited) response body. The body is read through io.LimitReader(resp.Body, maxResponseSize+1) so oversized bodies are handled separately; this error indicates a genuine transport problem mid-read — the connection was closed, reset, or timed out before the body completed.","triggerScenarios":"The server or an intermediary closes/resets the TCP connection partway through the response body, a proxy terminates the stream, or the context deadline (25s) expires during body transfer.","commonSituations":"Flaky mobile/VPN connections, aggressive CDN idle timeouts cutting large HTML pages short, TLS interception proxies resetting streams.","solutions":["Retry the request once — this is typically transient","Check whether a proxy/firewall between the host and the site truncates large responses","Increase the timeout budget if body transfer is slow","Log the wrapped *url.Error to confirm it is io.ErrUnexpectedEOF/connection-reset class"],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"if err != nil && errors.Is(err, io.ErrUnexpectedEOF) {\n    // transient truncation: retry once with fresh request\n}","preventionTips":["Retry truncated reads — usually transient","Check intermediary proxies/firewalls for stream-terminating behavior","Keep the LimitReader guard so huge/partial bodies fail fast","Monitor for correlated failures with error 241 (same connection path)"],"tags":["network","io","http"],"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"}