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

  1. Retry; if consistent, the mirror/proxy is mislabeling encodings — switch mirrors or bypass the proxy.
  2. Verify with curl -H 'Accept-Encoding: gzip' -v whether the body truly is gzip when the header claims so.
  3. Disable Accept-Encoding: gzip in the plugin's request headers so the server returns identity encoding.
  4. 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

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 {
			return

View on GitHub (pinned to beaa561337)