fish2018/pansou · error

[ ] 解码搜索结果失败

Error message

[%s] 解码搜索结果失败: %w

What it means

The raw response bytes could not be converted from GB18030 to UTF-8 by decodeGB18030, so the plugin cannot proceed to HTML parsing. This means the body is not valid GB18030 — typically because the site changed its encoding (e.g. now serving UTF-8) or returned compressed/binary/garbage content. The wrapped error comes from the GB18030 decoder (golang.org/x/text).

Solutions

  1. Check the response's Content-Type charset and <meta charset> to confirm the actual encoding; update decodeGB18030 usage if the site switched to UTF-8.
  2. Ensure gzip handling: set Accept-Encoding explicitly or wrap resp.Body with gzip.NewReader when Content-Encoding is gzip.
  3. Inspect the first bytes of the body (hex dump) to detect compressed or binary content.
  4. Fall back to decoding as UTF-8 when GB18030 decoding fails.

Example fix

// before
decoded, err := decodeGB18030(body)
if err != nil {
	return nil, fmt.Errorf("[%s] 解码搜索结果失败: %w", p.Name(), err)
}
// after
decoded, err := decodeGB18030(body)
if err != nil {
	if utf8.Valid(body) {
		decoded = string(body) // site switched to UTF-8
	} else {
		return nil, fmt.Errorf("[%s] 解码搜索结果失败: %w", p.Name(), err)
	}
}
Defensive patterns

Strategy: fallback

Validate before calling

if !utf8.Valid(body) && !looksLikeGB18030(body) {
	return fmt.Errorf("body is neither valid UTF-8 nor GB18030")
}

Type guard

func isUTF8(b []byte) bool { return utf8.Valid(b) }

Try / catch

decoded, err := decodeGB18030(body)
if err != nil {
	if utf8.Valid(body) { decoded = string(body) } else { return nil, fmt.Errorf("[%s] 解码搜索结果失败: %w", p.Name(), err) }
}

Prevention

When it happens

Trigger: decodeGB18030(body) errors in fetchSearch: body bytes are not decodable as GB18030 — the site switched to UTF-8, the response is gzip/deflate that was not decompressed, or a CAPTCHA/binary page was returned instead of HTML.

Common situations: Target site migrated to UTF-8 while the plugin still assumes GB18030; a reverse proxy or CDN serving compressed content without the plugin requesting/handling it; an HTML error or challenge page with bytes the decoder rejects.

Related errors


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

Appendix: source

Thrown at plugin/dygang/dygang.go:193

		return nil, fmt.Errorf("[%s] 创建搜索请求失败: %w", p.Name(), err)
	}
	setHeaders(req, baseURL+"/")
	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
	resp, err := client.Do(req)
	if err != nil {
		return nil, fmt.Errorf("[%s] 搜索请求失败: %w", p.Name(), err)
	}
	defer resp.Body.Close()
	if resp.StatusCode != http.StatusOK {
		return nil, fmt.Errorf("[%s] 搜索请求返回 HTTP %d", p.Name(), resp.StatusCode)
	}
	body, err := io.ReadAll(io.LimitReader(resp.Body, 4<<20))
	if err != nil {
		return nil, fmt.Errorf("[%s] 读取搜索结果失败: %w", p.Name(), err)
	}
	decoded, err := decodeGB18030(body)
	if err != nil {
		return nil, fmt.Errorf("[%s] 解码搜索结果失败: %w", p.Name(), err)
	}
	doc, err := goquery.NewDocumentFromReader(strings.NewReader(decoded))
	if err != nil {
		return nil, fmt.Errorf("[%s] 解析搜索结果失败: %w", p.Name(), err)
	}
	return doc, nil
}

func (p *Plugin) fetchDetail(client *http.Client, detailURL string) ([]magnetItem, string, string) {
	ctx, cancel := context.WithTimeout(context.Background(), requestTimeout)
	defer cancel()
	req, err := http.NewRequestWithContext(ctx, http.MethodGet, detailURL, nil)
	if err != nil {
		return nil, "", ""
	}
	setHeaders(req, baseURL+"/")
	resp, err := client.Do(req)
	if err != nil {

View on GitHub (pinned to beaa561337)