{"record":{"id":"2b87fc023f0538a7","repo":"fish2018/pansou","slug":"w-2b87fc","errorCode":null,"errorMessage":"读取详情页响应失败: %w","messagePattern":"读取详情页响应失败: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"plugin/wuji/wuji.go","lineNumber":329,"sourceCode":"\t// 设置请求头\n\tp.setRequestHeaders(req)\n\t\n\t// 发送HTTP请求\n\tresp, err := p.doRequestWithRetry(req, client)\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"详情页请求失败: %w\", err)\n\t}\n\tdefer resp.Body.Close()\n\t\n\t// 检查状态码\n\tif resp.StatusCode != 200 {\n\t\treturn \"\", fmt.Errorf(\"详情页返回状态码: %d\", resp.StatusCode)\n\t}\n\t\n\t// 读取响应体内容\n\tbody, err := io.ReadAll(resp.Body)\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"读取详情页响应失败: %w\", err)\n\t}\n\t\n\t// 解析HTML\n\tdoc, err := goquery.NewDocumentFromReader(strings.NewReader(string(body)))\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"详情页HTML解析失败: %w\", err)\n\t}\n\t\n\t// 提取磁力链接\n\tmagnetInput := doc.Find(\"input#input-magnet\")\n\tif magnetInput.Length() == 0 {\n\t\treturn \"\", fmt.Errorf(\"未找到磁力链接输入框\")\n\t}\n\t\n\tmagnetLink, exists := magnetInput.Attr(\"value\")\n\tif !exists || magnetLink == \"\" {\n\t\treturn \"\", fmt.Errorf(\"磁力链接为空\")\n\t}","sourceCodeStart":311,"sourceCodeEnd":347,"githubUrl":"https://github.com/fish2018/pansou/blob/beaa56133755a548ebc51b090b3816e2ae044aa6/plugin/wuji/wuji.go#L311-L347","documentation":"fetchMagnetLink reads the entire detail-page response body with io.ReadAll and this error wraps any read failure — the response body is a network stream, so this is usually a mid-transfer connection drop, timeout, or decompression error rather than a disk problem.","triggerScenarios":"io.ReadAll(resp.Body) fails while streaming the detail page: connection reset by peer mid-response, the TimeoutSeconds context deadline expiring during body transfer, gzip/deflate decode errors, or chunked-encoding corruption.","commonSituations":"Slow or unstable network to the target site; server closing connections early under load or anti-bot measures; proxy/CDN terminating long responses; the response being gzip-encoded but the decompressor rejecting it.","solutions":["Retry the request — transient connection resets are common; doRequestWithRetry already retried the initial Do but not the body read.","Increase TimeoutSeconds if large pages exceed the deadline during body transfer.","Check for TLS-intercepting proxies/firewalls truncating responses; test with curl --compressed from the same host.","Set a bound read (io.LimitReader) if huge responses are a concern, and log body-read progress for large pages.","If Content-Encoding mismatch is suspected, verify the client's Transport has automatic decompression enabled (Accept-Encoding handling)."],"exampleFix":"// before\nbody, err := io.ReadAll(resp.Body)\nif err != nil {\n    return \"\", fmt.Errorf(\"读取详情页响应失败: %w\", err)\n}\n// after\nbody, err := io.ReadAll(io.LimitReader(resp.Body, maxBodySize))\nif err != nil {\n    if errors.Is(err, context.DeadlineExceeded) {\n        return \"\", fmt.Errorf(\"detail body read timed out for %s: %w\", detailURL, err)\n    }\n    return \"\", fmt.Errorf(\"读取详情页响应失败: %w\", err)\n}","handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"magnet, err := p.fetchMagnetLink(client, detailURL)\nif err != nil && strings.Contains(err.Error(), \"读取详情页响应失败\") {\n    // transient body read failure: retry once after short delay\n    time.Sleep(time.Second)\n    magnet, err = p.fetchMagnetLink(client, detailURL)\n}","preventionTips":["Retry body reads — mid-transfer resets are usually transient","Use io.LimitReader to bound response size","Ensure automatic gzip handling in http.Transport","Increase timeout for large pages"],"tags":["network","http","io","scraping"],"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"}