fish2018/pansou · error
创建gzip reader失败
Error message
创建gzip reader失败: %w
What it means
getResponseReader manually decompresses responses whose Content-Encoding header is gzip (the client presumably doesn't auto-decompress). gzip.NewReader(resp.Body) validates the gzip header immediately; if the body isn't actually gzip data, this error wraps 'gzip: invalid header' and the caller aborts.
Solutions
- Retry; if consistent, the mirror/proxy is mislabeling encodings — switch mirrors or bypass the proxy.
- Verify with curl -H 'Accept-Encoding: gzip' -v whether the body truly is gzip when the header claims so.
- Disable Accept-Encoding: gzip in the plugin's request headers so the server returns identity encoding.
- Patch getResponseReader to sniff magic bytes (1f 8b) before creating the gzip reader and fall back to the raw body.
Example fix
// before
if contentEncoding == "gzip" {
gzReader, err := gzip.NewReader(resp.Body)
if err != nil {
return nil, fmt.Errorf("创建gzip reader失败: %w", err)
}
reader = gzReader
}
// after: sniff magic bytes and fall back to raw body
if contentEncoding == "gzip" {
br := bufio.NewReader(resp.Body)
magic, _ := br.Peek(2)
if len(magic) == 2 && magic[0] == 0x1f && magic[1] == 0x8b {
gzReader, err := gzip.NewReader(br)
if err != nil {
return nil, fmt.Errorf("创建gzip reader失败: %w", err)
}
reader = gzReader
} else {
log.Printf("[Xb6v] Content-Encoding为gzip但body非gzip,按原文读取")
reader = br
}
} Defensive patterns
Strategy: validation
Validate before calling
func isGzip(body []byte) bool { return len(body) >= 2 && body[0] == 0x1f && body[1] == 0x8b } Type guard
func isGzipError(err error) bool { return err != nil && strings.Contains(err.Error(), "gzip: invalid header") } Try / catch
results, err := pluginSearch(keyword)
if err != nil && isGzipError(err) {
// server mislabels Content-Encoding — retry without gzip or switch mirror
} Prevention
- Bypass or fix proxies that rewrite Content-Encoding headers.
- Verify mirror responses with curl --compressed before relying on them.
- Send no Accept-Encoding (identity) if the mirror mishandles gzip.
When it happens
Trigger: Server (or an intermediary like a misconfigured proxy/CDN) sends Content-Encoding: gzip but the body is plain text/HTML, chunked garbage, or an error page — gzip.NewReader fails on the first bytes. Called from searchImpl and fetchDetailPageMagnetLinks for every xb6v response.
Common situations: Reverse proxy (nginx) double-encoding or mislabeling; site serving brotli/deflate mislabeled as gzip; anti-bot layer returning a plain challenge body with stale compression headers; TLS-terminating proxy altering the body.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
AI-assisted analysis of fish2018/pansou@beaa561337 (2026-09-07).
Data as JSON: /api/errors/0305baf040079b66.
Report an issue: GitHub.
Appendix: source
Thrown at plugin/xb6v/xb6v.go:356
return keywordFilteredResults, nil
}
// getResponseReader 获取响应读取器(处理gzip压缩)
func (p *Xb6vPlugin) getResponseReader(resp *http.Response) (io.Reader, error) {
var reader io.Reader = resp.Body
// 检查Content-Encoding
contentEncoding := resp.Header.Get("Content-Encoding")
if p.debugMode {
log.Printf("[Xb6v] Content-Encoding: %s", contentEncoding)
}
// 如果是gzip压缩,手动解压
if contentEncoding == "gzip" {
gzReader, err := gzip.NewReader(resp.Body)
if err != nil {
return nil, fmt.Errorf("创建gzip reader失败: %w", err)
}
reader = gzReader
}
return reader, nil
}
// extractDetailURLs 从搜索结果页面提取详情页链接和日期
func (p *Xb6vPlugin) extractDetailURLs(doc *goquery.Document) []DetailPageInfo {
var detailPages []DetailPageInfo
urlMap := make(map[string]bool) // 去重
// 只从搜索结果区域提取链接,搜索结果在 ul#post_container 中
doc.Find("ul#post_container li.post").Each(func(i int, li *goquery.Selection) {
// 提取详情页链接
linkEl := li.Find("a[href*='.html']")
if linkEl.Length() == 0 {
returnView on GitHub (pinned to beaa561337)