fish2018/pansou · error

[ ] 第 页请求返回状态码

Error message

[%s] 第%d页请求返回状态码: %d

What it means

searchPage requires HTTP 200 from the search endpoint. Any other status (403 bot-block, 404 gone mirror, 429 rate limit, 5xx server error) produces this error carrying the page number and status code. Unlike 723, the request succeeded at transport level — the server answered with a non-200 status.

Solutions

  1. Log the response body snippet for the failing status to identify bot challenges vs dead pages.
  2. Switch to a working mirror domain in the plugin configuration/constants.
  3. Slow down request rate or add jitter between page fetches to avoid 429s.
  4. Ensure realistic browser headers (User-Agent, Accept, Referer) are present — they already are; consider cookie handling for challenge pages.
  5. Handle 5xx with the existing retry mechanism by treating retryable statuses in doRequestWithRetry.

Example fix

// before
if resp.StatusCode != 200 {
    return nil, 0, fmt.Errorf("[%s] 第%d页请求返回状态码: %d", p.Name(), page, resp.StatusCode)
}
// after: retry transient statuses
code := resp.StatusCode
if code == 429 || code >= 500 {
    io.Copy(io.Discard, resp.Body)
    resp.Body.Close()
    time.Sleep(2 * time.Second)
    return p.searchPage(ctx, keyword, page) // bounded by caller
}
if code != 200 {
    return nil, 0, fmt.Errorf("[%s] 第%d页请求返回状态码: %d", p.Name(), page, code)
}
Defensive patterns

Strategy: fallback

Validate before calling

resp, err := http.Head(searchURL)
if err == nil && resp.StatusCode != 200 {
    return fmt.Errorf("mirror returned %d before searching, switch mirror", resp.StatusCode)
}

Type guard

func isRetryableStatus(code int) bool {
    return code == 429 || code >= 500
}
func isBlockStatus(code int) bool {
    return code == 403 || code == 503
}

Try / catch

results, total, err := plugin.Search(keyword, page)
var statusErr error
if err != nil && strings.Contains(err.Error(), "请求返回状态码") {
    if strings.Contains(err.Error(), ": 403") || strings.Contains(err.Error(), ": 503") {
        results, total, err = searchViaMirror(keyword, page) // bot-blocked: try alternate mirror/resolver
    } else {
        results, total, err = retryWithBackoff(2, func() ([]model.Item, int, error) {
            return plugin.Search(keyword, page)
        })
    }
}

Prevention

When it happens

Trigger: doRequestWithRetry returns a response whose StatusCode != 200 during a searchPage call: Cloudflare/anti-bot challenge page, mirror moved (404), too many rapid requests (429), or upstream outage (500/502/503).

Common situations: Mirror domain blocked/changed so requests hit a parking page; scraping too fast triggers rate limiting; missing/rotated User-Agent gets flagged by anti-bot; the .xyz mirror is dead.

Related errors


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

Appendix: source

Thrown at plugin/thepiratebay/thepiratebay.go:272

	// 5. 设置完整的请求头 - 参考插件开发指南的最佳实践
	req.Header.Set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36")
	req.Header.Set("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8")
	req.Header.Set("Accept-Language", "zh-CN,zh;q=0.9,en;q=0.8")
	req.Header.Set("Connection", "keep-alive")
	req.Header.Set("Upgrade-Insecure-Requests", "1")
	req.Header.Set("Cache-Control", "max-age=0")
	req.Header.Set("Referer", "https://thpibay.xyz/")
	
	// 6. 发送HTTP请求(带重试机制)
	resp, err := p.doRequestWithRetry(req, client)
	if err != nil {
		return nil, 0, fmt.Errorf("[%s] 第%d页搜索请求失败: %w", p.Name(), page, err)
	}
	defer resp.Body.Close()
	
	// 7. 检查状态码
	if resp.StatusCode != 200 {
		return nil, 0, fmt.Errorf("[%s] 第%d页请求返回状态码: %d", p.Name(), page, resp.StatusCode)
	}
	
	// 8. 解析HTML响应
	doc, err := goquery.NewDocumentFromReader(resp.Body)
	if err != nil {
		return nil, 0, fmt.Errorf("[%s] 第%d页HTML解析失败: %w", p.Name(), page, err)
	}
	
	// 9. 解析分页信息(只在第一页解析)
	totalPages := 1
	if page == 1 {
		totalPages = p.parseTotalPages(doc)
	}
	
	// 10. 提取搜索结果
	results := make([]model.SearchResult, 0)
	doc.Find("table#searchResult tr").Each(func(i int, s *goquery.Selection) {
		// 跳过表头

View on GitHub (pinned to beaa561337)