fish2018/pansou · error

[ ] 搜索请求返回 HTTP

Error message

[%s] 搜索请求返回 HTTP %d

What it means

The HTTP request succeeded but the server responded with a status code other than 200 OK, so the plugin refuses to parse the body and returns this error. The site likely returned a redirect to a captcha/login page, a 403 anti-bot response, a 404, or a 5xx server error. Note the message does not wrap an underlying error — the status code itself is the information.

Solutions

  1. Log or inspect resp.StatusCode (and the body) to identify what the server actually returned.
  2. Update the plugin's baseURL/searchPath if the site moved (404 case).
  3. Check cookies/headers: add realistic User-Agent and reuse cookies if the site requires a session (403/captcha case).
  4. Back off and retry later for 5xx responses.

Example fix

// before
if resp.StatusCode != http.StatusOK {
	return nil, fmt.Errorf("[%s] 搜索请求返回 HTTP %d", p.Name(), resp.StatusCode)
}
// after
if resp.StatusCode != http.StatusOK {
	snippet, _ := io.ReadAll(io.LimitReader(resp.Body, 512))
	return nil, fmt.Errorf("[%s] 搜索请求返回 HTTP %d, body: %s", p.Name(), resp.StatusCode, snippet)
}
Defensive patterns

Strategy: try-catch

Try / catch

if resp.StatusCode != http.StatusOK {
	return fmt.Errorf("HTTP %d: inspect headers/body for captcha, redirect, or outage", resp.StatusCode)
}

Prevention

When it happens

Trigger: After client.Do, resp.StatusCode != http.StatusOK for the POST to baseURL+searchPath — e.g. 403 from WAF/anti-bot, 404 after a site URL structure change, 302 to a verification page, 500/502/503 from the upstream server.

Common situations: The target site changed its URL or enabled anti-scraping (Cloudflare challenge), an outdated baseURL in config, rate-limiting after frequent searches, or transient upstream outages.

Related errors


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

Appendix: source

Thrown at plugin/dygang/dygang.go:185

	if err != nil {
		return nil, fmt.Errorf("[%s] 编码搜索关键词失败: %w", p.Name(), err)
	}
	form := "tempid=1&tbname=article&keyboard=" + url.QueryEscape(string(encoded)) + "&show=title%2Csmalltext&Submit="
	ctx, cancel := context.WithTimeout(context.Background(), requestTimeout)
	defer cancel()
	req, err := http.NewRequestWithContext(ctx, http.MethodPost, baseURL+searchPath, strings.NewReader(form))
	if err != nil {
		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)

View on GitHub (pinned to beaa561337)