fish2018/pansou · error

创建gzip reader失败

Error message

创建gzip reader失败: %w

What it means

getResponseReader inspects Content-Encoding and, when it is gzip, wraps resp.Body in a gzip.Reader. This error means gzip.NewReader failed — the server declared gzip but the body is not valid gzip data (corrupt, already decompressed by a proxy, or empty).

Solutions

  1. Log and inspect the first bytes: valid gzip starts with 0x1f 0x8b; if absent, use the raw body
  2. Fix/avoid the proxy that decompresses without stripping Content-Encoding
  3. Set Accept-Encoding manually and handle decompression yourself for full control
  4. Fall back to the raw body when gzip.NewReader fails instead of aborting the search
  5. Check for odd Content-Encoding values like "gzip, br" that the simple equality check mishandles

Example fix

// before
gzReader, err := gzip.NewReader(resp.Body)
if err != nil {
    return nil, fmt.Errorf("创建gzip reader失败: %w", err)
}
// after
gzReader, err := gzip.NewReader(resp.Body)
if err != nil {
    // body may not actually be gzip; fall back to raw
    if ok, _ := resp.Body.(io.Seeker); ok != nil {
        resp.Body.Seek(0, io.SeekStart)
    }
    return resp.Body, nil
}
Defensive patterns

Strategy: fallback

Validate before calling

// only expect gzip when we sent Accept-Encoding: gzip and no proxy stripped it
enc := resp.Header.Get("Content-Encoding")
magic, _ := io.ReadAll(io.LimitReader(resp.Body, 2))
if enc == "gzip" && !(len(magic) == 2 && magic[0] == 0x1f && magic[1] == 0x8b) {
    log.Printf("declared gzip but body is not gzip (magic=%x)", magic)
}

Type guard

func isGzip(b []byte) bool {
    return len(b) >= 2 && b[0] == 0x1f && b[1] == 0x8b
}

Try / catch

reader, err := p.getResponseReader(resp)
if err != nil {
    if strings.Contains(err.Error(), "创建gzip reader失败") {
        // fall back to treating the body as plain text
        reader = resp.Body
    } else {
        return nil, err
    }
}

Prevention

When it happens

Trigger: Response has Content-Encoding: gzip but gzip.NewReader(resp.Body) errors: body already decompressed by middleware/proxy that forgot to strip the header, truncated body, empty body on an error response, or server mislabeling encoding.

Common situations: A reverse proxy (nginx) or service mesh decompressed the body without removing Content-Encoding; a transparent proxy mangles the stream; site sends malformed gzip under load; transparently handling both compressed and plain responses.

Related errors


AI-assisted analysis of fish2018/pansou@beaa561337 (2026-09-07). Data as JSON: /api/errors/62c3b4ede0542c70. Report an issue: GitHub.

Appendix: source

Thrown at plugin/leijing/leijing.go:186

	
	return filteredResults, nil
}

// getResponseReader 获取响应读取器(处理gzip压缩)
func (p *LeijingPlugin) 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("[Leijing] 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
}

// extractSearchResults 从HTML中提取搜索结果
func (p *LeijingPlugin) extractSearchResults(doc *goquery.Document, keyword string) []model.SearchResult {
	var results []model.SearchResult
	
	// 选择所有搜索结果项
	doc.Find(".topicItem").Each(func(i int, s *goquery.Selection) {
		// 提取标题和详情页链接
		titleElem := s.Find(".title a")
		title := strings.TrimSpace(titleElem.Text())
		detailPath, _ := titleElem.Attr("href")
		

View on GitHub (pinned to beaa561337)