fish2018/pansou · error

[ ] 第 页搜索请求失败

Error message

[%s] 第%d页搜索请求失败: %w

What it means

fetchPage executes the search request through doRequestWithRetry, which retries non-200 responses and network errors. If all attempts fail, the last error is wrapped with the plugin name and page number. This is the terminal network-failure error for a page fetch.

Solutions

  1. Inspect the wrapped cause (%w) to distinguish timeout/connection vs status-code failures.
  2. Add backoff/jitter between retries and cap retry count to avoid triggering rate limits.
  3. Rotate User-Agent / add delays if the site blocks scripted requests.
  4. Verify network connectivity and proxy settings in the deployment environment.
Defensive patterns

Strategy: retry

Validate before calling

if err := connectivityProbe(searchHost); err != nil {
	return fmt.Errorf("network unreachable before search: %w", err)
}

Type guard

func isRetryableNetErr(err error) bool {
	var ne net.Error
	return errors.As(err, &ne) || errors.Is(err, syscall.ECONNRESET) || errors.Is(err, syscall.ECONNREFUSED)
}

Try / catch

pr, err := fetchPage(page, keyword)
if err != nil {
	var ne net.Error
	if errors.As(err, &ne) && ne.Timeout() {
		time.Sleep(2 * time.Second)
		pr, err = fetchPage(page, keyword)
	}
	if err != nil { return nil, err }
}

Prevention

When it happens

Trigger: Every attempt in doRequestWithRetry failed: timeouts, connection refused/reset, TLS errors, or the site kept returning non-OK status codes (see error 819 for the non-200 cause).

Common situations: Site is down or rate-limiting your IP; aggressive retry loop triggered anti-bot blocking; proxy misconfigured; DNS failure in the deployment environment; page number beyond what the site supports.

Understand the failure class

Background: 'Something went wrong' / 'Request failed (500)' / 'HTTP error! status: 404' — what failed HTTP requests actually mean and how to find the real cause — this error's family across 28 libraries.

Related errors


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

Appendix: source

Thrown at plugin/xiaoyu/xiaoyu.go:158

	}

	return plugin.FilterResultsByKeyword(results, keyword), nil
}

func (p *XiaoyuPlugin) fetchPage(client *http.Client, keyword string, page int) (pageResult, error) {
	requestURL := fmt.Sprintf(searchURL, page, url.PathEscape(keyword))
	ctx, cancel := context.WithTimeout(context.Background(), requestTimeout)
	defer cancel()

	req, err := http.NewRequestWithContext(ctx, http.MethodGet, requestURL, nil)
	if err != nil {
		return pageResult{}, fmt.Errorf("[%s] 创建第%d页请求失败: %w", p.Name(), page, err)
	}
	setRequestHeaders(req)

	resp, err := doRequestWithRetry(client, req)
	if err != nil {
		return pageResult{}, fmt.Errorf("[%s] 第%d页搜索请求失败: %w", p.Name(), page, err)
	}
	defer resp.Body.Close()

	doc, err := goquery.NewDocumentFromReader(io.LimitReader(resp.Body, maxResponseSize))
	if err != nil {
		return pageResult{}, fmt.Errorf("[%s] 第%d页解析失败: %w", p.Name(), page, err)
	}

	return parsePage(doc), nil
}

func setRequestHeaders(req *http.Request) {
	req.Header.Set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 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("Referer", baseURL+"/")
}

View on GitHub (pinned to beaa561337)