fish2018/pansou · error

[ ] 详情页返回状态码

Error message

[%s] 详情页返回状态码: %d

What it means

This error is raised by fetchDetailData in the Mizixing plugin when the detail page HTTP response does not return status 200. The plugin aborts parsing because the body likely does not contain the expected HTML article structure. It wraps the plugin name and the actual status code so the caller knows which upstream response failed.

Solutions

  1. Log the status code and check the target site availability in a browser or with curl to identify whether it's 4xx (URL/blocking) or 5xx (server side)
  2. Ensure a realistic User-Agent/browser-like header set is sent to avoid 403 anti-bot responses
  3. Add or increase retry with backoff for transient 5xx/429 responses before failing
  4. Verify the detail URL is built from a valid, current item ID returned by search
  5. Handle non-200 gracefully upstream (skip the item) instead of crashing the whole search run

Example fix

// before
resp, err := p.doRequest(req)
if resp.StatusCode != http.StatusOK {
    return detailData{}, fmt.Errorf("[%s] 详情页返回状态码: %d", p.Name(), resp.StatusCode)
}
// after
resp, err := p.doRequest(req)
if err != nil {
    return detailData{}, err
}
if resp.StatusCode == http.StatusTooManyRequests || resp.StatusCode >= 500 {
    if r, rerr := p.doRequestWithRetry(req); rerr == nil {
        resp = r
    }
}
if resp.StatusCode != http.StatusOK {
    return detailData{}, fmt.Errorf("[%s] 详情页返回状态码: %d", p.Name(), resp.StatusCode)
}
Defensive patterns

Strategy: retry

Validate before calling

// pre-check before calling search
detailURL := buildDetailURL(id)
if u, err := url.Parse(detailURL); err != nil || u.Scheme == "" || u.Host == "" {
    return fmt.Errorf("invalid detail url: %s", detailURL)
}

Try / catch

detail, err := p.fetchDetailData(id)
if err != nil {
    var httpErr interface{ Unwrap() error }
    log.Printf("detail fetch failed, skipping item: %v", err)
    return fallbackResult(id) // degrade gracefully
}

Prevention

When it happens

Trigger: Triggered whenever an HTTP GET to the Mizixing detail page completes but resp.StatusCode != http.StatusOK (e.g. 403 from anti-bot protection, 404 for a stale detail URL, 429 rate limiting, 5xx server errors).

Common situations: Site temporarily down or under maintenance; IP blocked by WAF/CDN; the detail URL was constructed from an outdated or invalid item ID; heavy scraping triggering rate limits.

Related errors


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

Appendix: source

Thrown at plugin/mizixing/mizixing.go:254

func (p *MizixingPlugin) fetchDetailData(client *http.Client, detailURL string) (detailData, error) {
	ctx, cancel := context.WithTimeout(context.Background(), detailTimeout)
	defer cancel()

	req, err := http.NewRequestWithContext(ctx, http.MethodGet, detailURL, nil)
	if err != nil {
		return detailData{}, fmt.Errorf("[%s] 创建详情页请求失败: %w", p.Name(), err)
	}
	setHTMLHeaders(req, detailURL)

	resp, err := p.doRequestWithRetry(req, client, maxRequestRetries)
	if err != nil {
		return detailData{}, err
	}
	defer resp.Body.Close()

	if resp.StatusCode != http.StatusOK {
		return detailData{}, fmt.Errorf("[%s] 详情页返回状态码: %d", p.Name(), resp.StatusCode)
	}

	doc, err := goquery.NewDocumentFromReader(resp.Body)
	if err != nil {
		return detailData{}, fmt.Errorf("[%s] 解析详情页失败: %w", p.Name(), err)
	}

	content := doc.Find("article.article-content")
	if content.Length() == 0 {
		content = doc.Find(".article-content")
	}
	if content.Length() == 0 {
		content = doc.Find(".entry-content")
	}
	if content.Length() == 0 {
		content = doc.Selection
	}

View on GitHub (pinned to beaa561337)