fish2018/pansou · error

[ ] 搜索请求返回 HTTP

Error message

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

What it means

fetchSearch rejects any non-200 status from the leso search endpoint with this message, including the plugin name and the numeric status. The server responded, but the search POST was not accepted (anti-bot challenge, rate limit, moved endpoint, server error).

Solutions

  1. Log a body snippet with the status to see whether it's a captcha, redirect, or error page
  2. Send realistic browser headers (User-Agent, Referer, cookies) to pass bot checks
  3. Update the mirror's base URL if the site moved or the search path changed
  4. Back off and retry on 429/5xx; reduce crawl rate to avoid throttling
  5. If a login is now required, supply session cookies in the client's Jar

Example fix

// before
return nil, fmt.Errorf("[%s] 搜索请求返回 HTTP %d", p.Name(), resp.StatusCode)
// after
snip, _ := io.ReadAll(io.LimitReader(resp.Body, 256))
return nil, fmt.Errorf("[%s] 搜索请求返回 HTTP %d, body: %s", p.Name(), resp.StatusCode, snip)
Defensive patterns

Strategy: retry

Validate before calling

// pre-flight status probe of the search endpoint
resp, err := client.Get(baseURL + "/search.php?searchsubmit=yes")
if err == nil {
    resp.Body.Close()
    if resp.StatusCode == http.StatusForbidden {
        log.Printf("leso is bot-blocking this client")
    }
}

Try / catch

doc, err := plugin.fetchSearch(client, baseURL, keyword)
if err != nil {
    var statusErr *fmt.Errorf
    if errors.As(err, &statusErr) && strings.Contains(err.Error(), "HTTP 4") {
        // 4xx: switch mirror or add credentials; don't retry immediately
        return alternateMirrorSearch(keyword)
    }
    if strings.Contains(err.Error(), "HTTP 5") {
        // 5xx: retry with backoff
        time.Sleep(2 * time.Second)
        return plugin.fetchSearch(client, baseURL, keyword)
    }
    return err
}

Prevention

When it happens

Trigger: client.Do succeeded but resp.StatusCode != http.StatusOK — e.g. Discuz-style forum returns 403 for bot traffic, 301 to a new domain not followed, 429 rate limit, or 5xx outage.

Common situations: Leso mirror enabled anti-bot/Cloudflare protection; forum requires login/cookies for search; rate limiting after aggressive crawling; mirror domain changed so old URL redirects or 404s.

Related errors


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

Appendix: source

Thrown at plugin/leso/leso.go:153

	form := url.Values{}
	form.Set("mod", "forum")
	form.Set("srchtxt", keyword)
	form.Set("searchsubmit", "yes")
	ctx, cancel := context.WithTimeout(context.Background(), requestTimeout)
	defer cancel()
	req, err := http.NewRequestWithContext(ctx, http.MethodPost, baseURL+"/search.php?searchsubmit=yes", strings.NewReader(form.Encode()))
	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)
	}
	doc, err := goquery.NewDocumentFromReader(io.LimitReader(resp.Body, 6<<20))
	if err != nil {
		return nil, fmt.Errorf("[%s] 解析搜索结果失败: %w", p.Name(), err)
	}
	return doc, nil
}

func (p *Plugin) fetchDetail(client *http.Client, item searchItem) (model.SearchResult, bool) {
	ctx, cancel := context.WithTimeout(context.Background(), requestTimeout)
	defer cancel()
	req, err := http.NewRequestWithContext(ctx, http.MethodGet, item.detailURL, nil)
	if err != nil {
		return model.SearchResult{}, false
	}
	setHeaders(req, baseURL+"/")
	resp, err := client.Do(req)
	if err != nil {

View on GitHub (pinned to beaa561337)