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
- Log and inspect the first bytes: valid gzip starts with 0x1f 0x8b; if absent, use the raw body
- Fix/avoid the proxy that decompresses without stripping Content-Encoding
- Set Accept-Encoding manually and handle decompression yourself for full control
- Fall back to the raw body when gzip.NewReader fails instead of aborting the search
- 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
- Send an explicit Accept-Encoding header and decode it yourself
- Fix proxies that decompress bodies without stripping Content-Encoding
- Check the gzip magic bytes (0x1f 0x8b) before constructing a gzip.Reader
- Handle multi-encoding values like "gzip, br" explicitly
- Log first bytes when decompression fails for quick diagnosis
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)