{"record":{"id":"8310ba9d81b0994d","repo":"fish2018/pansou","slug":"w-8310ba","errorCode":null,"errorMessage":"读取响应失败: %w","messagePattern":"读取响应失败: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"plugin/pansearch/pansearch.go","lineNumber":434,"sourceCode":"\tif resp.StatusCode != 200 {\n\t\t// 如果状态码不是200，但有旧的缓存，使用旧的缓存（优雅降级）\n\t\tif buildIdCache != \"\" {\n\t\t\tfmt.Printf(\"获取buildId时服务器返回非200状态码: %d，使用旧的buildId\\n\", resp.StatusCode)\n\t\t\treturn buildIdCache, nil\n\t\t}\n\t\treturn \"\", fmt.Errorf(\"获取buildId时服务器返回非200状态码: %d\", resp.StatusCode)\n\t}\n\n\t// 使用更高效的方式读取响应体\n\tvar bodyBuilder strings.Builder\n\t_, err = io.Copy(&bodyBuilder, resp.Body)\n\tif err != nil {\n\t\t// 如果读取响应失败，但有旧的缓存，使用旧的缓存（优雅降级）\n\t\tif buildIdCache != \"\" {\n\t\t\t// fmt.Printf(\"读取响应失败，使用旧的buildId: %v\\n\", err)\n\t\t\treturn buildIdCache, nil\n\t\t}\n\t\treturn \"\", fmt.Errorf(\"读取响应失败: %w\", err)\n\t}\n\tbody := bodyBuilder.String()\n\n\t// 使用提取函数获取 buildId\n\tbuildId := extractBuildId(body)\n\n\t// 如果提取失败，但有旧的缓存，使用旧的缓存（优雅降级）\n\tif buildId == \"\" {\n\t\tif buildIdCache != \"\" {\n\t\t\t// fmt.Println(\"未找到buildId，使用旧的buildId\")\n\t\t\treturn buildIdCache, nil\n\t\t}\n\t\treturn \"\", fmt.Errorf(\"未找到buildId\")\n\t}\n\n\t// 更新缓存\n\tbuildIdCache = buildId\n\tbuildIdCacheTime = time.Now()","sourceCodeStart":416,"sourceCodeEnd":452,"githubUrl":"https://github.com/fish2018/pansou/blob/beaa56133755a548ebc51b090b3816e2ae044aa6/plugin/pansearch/pansearch.go#L416-L452","documentation":"After the buildId HTTP response completes, io.Copy of the body into a buffer failed. Like the non-200 path, this error is only returned when there is no cached buildId to fall back on; otherwise the stale cached buildId is used silently.","triggerScenarios":"Calling getBuildId when reading the response body fails — typically connection reset mid-transfer, context/deadline exceeded while streaming the body, or the server closing the connection early — with an empty buildIdCache.","commonSituations":"Flaky network or proxy, upstream server aborting large/HTML responses, aggressive timeouts cutting off body reads.","solutions":["Retry the request; transient read errors often succeed on a second attempt.","Check network stability/proxy configuration between the host and the upstream site.","Increase timeout margins if deadline-exceeded is the wrapped cause.","Once a buildId is cached successfully, this path degrades to the cached value instead of erroring."],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"if err != nil && strings.Contains(err.Error(), \"读取响应失败\") {\n    // transient body read failure: retry once after short delay\n    time.Sleep(2 * time.Second)\n    results, err = plugin.Search(ctx, kw)\n}","preventionTips":["Ensure stable network connectivity to the upstream host","Avoid aggressively small client timeouts that can cut off body reads","Retry transient failures — the cached buildId path usually masks these after first success"],"tags":["http","network","io","response-body"],"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"}