fish2018/pansou · error

[ ] suggest 响应解析失败

Error message

[%s] suggest 响应解析失败: %w

What it means

Raised in searchSuggest (plugin/qiwei/qiwei.go:210) when the suggest endpoint's response body cannot be parsed as the expected suggestResponse JSON (code/msg/list). The json unmarshal error is wrapped with %w. Typically the site returned HTML (error page, verification page not caught by isVerifyPage, CDN block page) instead of the AJAX JSON payload.

Solutions

  1. Log/print the first ~200 bytes of body on this error to see what was actually returned (HTML vs JSON) — that determines the fix.
  2. If it's an unrecognized block/verification page, extend isVerifyPage's regexes in qiwei.go to detect it so the verification flow runs instead.
  3. If the API response shape changed, update the suggestResponse struct fields/tags.
  4. Retry with a different keyword or later; transient HTML error pages clear once upstream recovers.

Example fix

// before (debugging aid inside searchSuggest)
if err := json.Unmarshal([]byte(body), &resp); err != nil {
    return nil, fmt.Errorf("[%s] suggest 响应解析失败: %w", p.Name(), err)
}
// after
if err := json.Unmarshal([]byte(body), &resp); err != nil {
    return nil, fmt.Errorf("[%s] suggest 响应解析失败: %w, body=%q", p.Name(), err, body[:min(200, len(body))])
}
Defensive patterns

Strategy: validation

Validate before calling

// validate the body looks like the expected JSON before unmarshalling
trimmed := strings.TrimSpace(body)
if !strings.HasPrefix(trimmed, "{") {
    return fmt.Errorf("non-JSON suggest response (likely HTML): %.100s", trimmed)
}

Try / catch

var resp suggestResponse
if err := json.Unmarshal([]byte(body), &resp); err != nil {
    log.Printf("qiwei suggest returned non-JSON body: %.200s", body)
    return nil, fmt.Errorf("suggest parse failed: %w", err) // host loop will try next mirror
}

Prevention

When it happens

Trigger: json.Unmarshal([]byte(body), &resp) returns an error after a successful fetchBody of /index.php/ajax/suggest?mid=1&limit=100&wd=<keyword> — i.e. HTTP succeeded but the body is not the expected JSON object.

Common situations: Site is behind a CDN serving an HTML challenge/error page that isVerifyPage's huadong regex doesn't recognize; keyword edge cases hitting a non-AJAX fallback page; the site changed its suggest API response format; server returned an HTML 5xx error page with status 200.

Understand the failure class

Background: "failed to unmarshal" / json.Unmarshal errors: why parsing a response into a Go struct fails and how to fix it — this error's family across 23 libraries.

Related errors


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

Appendix: source

Thrown at plugin/qiwei/qiwei.go:210

	if err != nil {
		return nil, err
	}
	if isVerifyPage(body) {
		if err := p.solveVerification(client, searchURL, body); err != nil {
			return nil, fmt.Errorf("[%s] 搜索验证失败: %w", p.Name(), err)
		}
		body, err = p.fetchBody(client, searchURL, host+"/", searchTimeout)
		if err != nil {
			return nil, err
		}
		if isVerifyPage(body) {
			return nil, fmt.Errorf("[%s] 命中验证页: %s", p.Name(), host)
		}
	}

	var resp suggestResponse
	if err := json.Unmarshal([]byte(body), &resp); err != nil {
		return nil, fmt.Errorf("[%s] suggest 响应解析失败: %w", p.Name(), err)
	}

	if resp.Code != 1 && len(resp.List) == 0 {
		return nil, fmt.Errorf("[%s] suggest 响应异常: host=%s code=%d msg=%s", p.Name(), host, resp.Code, resp.Msg)
	}

	return resp.List, nil
}

func (p *QiweiPlugin) enrichResults(client *http.Client, host string, items []suggestItem, forceRefresh bool) []model.SearchResult {
	results := make([]model.SearchResult, len(items))
	var wg sync.WaitGroup
	sem := make(chan struct{}, maxConcurrent)

	for i, item := range items {
		wg.Add(1)
		go func(idx int, it suggestItem) {
			defer wg.Done()

View on GitHub (pinned to beaa561337)