{"record":{"id":"f4b288c9a7462601","repo":"fish2018/pansou","slug":"s-w-f4b288","errorCode":null,"errorMessage":"[%s] 读取搜索结果失败: %w","messagePattern":"\\[(.+?)\\] 读取搜索结果失败: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"plugin/5266ys/5266ys.go","lineNumber":190,"sourceCode":"\tctx, cancel := context.WithTimeout(context.Background(), requestTimeout)\n\tdefer cancel()\n\treq, err := http.NewRequestWithContext(ctx, http.MethodPost, baseURL+searchPath, strings.NewReader(form))\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"[%s] 创建搜索请求失败: %w\", p.Name(), err)\n\t}\n\tsetHeaders(req, baseURL+\"/\")\n\treq.Header.Set(\"Content-Type\", \"application/x-www-form-urlencoded\")\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, 4<<20))\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"[%s] 读取搜索结果失败: %w\", p.Name(), err)\n\t}\n\tdecoded, err := decodeGB18030(body)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"[%s] 解码搜索结果失败: %w\", p.Name(), err)\n\t}\n\tdoc, err := goquery.NewDocumentFromReader(strings.NewReader(decoded))\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"[%s] 解析搜索结果失败: %w\", p.Name(), err)\n\t}\n\treturn doc, nil\n}\n\nfunc (p *Plugin) fetchDetail(client *http.Client, detailURL string) ([]magnetItem, string, string) {\n\tctx, cancel := context.WithTimeout(context.Background(), requestTimeout)\n\tdefer cancel()\n\treq, err := http.NewRequestWithContext(ctx, http.MethodGet, detailURL, nil)\n\tif err != nil {\n\t\treturn nil, \"\", \"\"","sourceCodeStart":172,"sourceCodeEnd":208,"githubUrl":"https://github.com/fish2018/pansou/blob/beaa56133755a548ebc51b090b3816e2ae044aa6/plugin/5266ys/5266ys.go#L172-L208","documentation":"fetchSearch wraps an error from io.ReadAll(io.LimitReader(resp.Body, 4<<20)) — reading the response body failed mid-stream. The 4MB LimitReader caps memory use, so this indicates an actual I/O problem: the connection was reset or timed out while the body was being transferred, not an oversized page.","triggerScenarios":"The TCP connection drops, the server closes early, or the request context's deadline expires while io.ReadAll is draining resp.Body on a large search results page.","commonSituations":"Unstable network or a flaky proxy interrupting large HTML transfers; the site slow-throttles responses and the context deadline (requestTimeout) cuts the read short; intermediaries (CDN/WAF) terminating long-running connections.","solutions":["Check the wrapped %w error: 'context deadline exceeded' means requestTimeout elapsed during body read — increase requestTimeout.","Add a retry around fetchSearch for transient connection-reset errors.","If pages are legitimately near 4MB, raise the LimitReader cap (though most search pages are far smaller).","Test with curl from the same host to see whether the full body downloads reliably."],"exampleFix":"// before\nbody, err := io.ReadAll(io.LimitReader(resp.Body, 4<<20))\nif err != nil {\n    return nil, fmt.Errorf(\"[%s] 读取搜索结果失败: %w\", p.Name(), err)\n}\n// after\nbody, err := io.ReadAll(io.LimitReader(resp.Body, 4<<20))\nif err != nil {\n    return nil, fmt.Errorf(\"[%s] 读取搜索结果失败: %w\", p.Name(), err)\n}\n// 重新搜索时增加重试\nvar doc *goquery.Document\nfor i := 0; i < 3; i++ {\n    if doc, err = p.fetchSearch(client, keyword); err == nil {\n        break\n    }\n    time.Sleep(time.Second * time.Duration(i+1))\n}","handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"results, err := p.Search(ctx, keyword)\nif err != nil {\n    var netErr net.Error\n    if errors.As(err, &netErr) || errors.Is(err, io.ErrUnexpectedEOF) {\n        // 传输中断: 退避后重试\n    }\n}","preventionTips":["Use a timeout longer than the site's worst-case response time.","Retry transient I/O errors with backoff.","Avoid scraping over unstable proxies/VPNs.","Keep the LimitReader cap well above the page's actual size."],"tags":["go","http","io","network"],"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"}