fish2018/pansou · error

[ ] 网盘第 页返回状态码

Error message

[%s] %s网盘第%d页返回状态码: %d

What it means

After a successful round-trip, fetchSearchPage checks resp.StatusCode and throws this error for anything other than 200, embedding the plugin name, pan type, page number, and actual status code. It means the haisou API answered but rejected the request — e.g. 403/429 anti-bot or rate limiting, 404 after an endpoint change, or 5xx server trouble.

Solutions

  1. Log the status code and body to identify whether it's 403/404/429/5xx.
  2. Back off and retry for 429/5xx; reduce request rate.
  3. Update the search URL and required headers if the API changed (compare with browser DevTools).
  4. Use a session with proper cookies/headers if the site now requires them.

Example fix

// before
if resp.StatusCode != 200 {
    return nil, fmt.Errorf("...返回状态码: %d", resp.StatusCode)
}
// after
if resp.StatusCode == http.StatusTooManyRequests {
    time.Sleep(retryAfterBackoff(resp.Header.Get("Retry-After")))
    return p.fetchSearchPage(panType, keyword, pageNo) // retry once
} else if resp.StatusCode != 200 {
    return nil, fmt.Errorf("...返回状态码: %d", resp.StatusCode)
}
Defensive patterns

Strategy: retry

Validate before calling

// honor rate limiting proactively
if resp.StatusCode == http.StatusTooManyRequests || resp.StatusCode == http.StatusForbidden {
    return fmt.Errorf("throttled (status %d); back off before retrying", resp.StatusCode)
}

Type guard

func isThrottled(err error) bool { return err != nil && (strings.Contains(err.Error(), "429") || strings.Contains(err.Error(), "403")) }

Try / catch

items, err := fetchSearchPage(panType, keyword, pageNo)
if isThrottled(err) {
    select {
    case <-time.After(rateLimitBackoff):
    case <-ctx.Done():
        return ctx.Err()
    }
    items, err = fetchSearchPage(panType, keyword, pageNo)
}

Prevention

When it happens

Trigger: Calling fetchSearchPage when the API returns a non-200 status: request missing expected headers/cookies, too-frequent requests triggering 429/403, endpoint path changed (404), or server-side errors (5xx).

Common situations: Site updated its API and moved/renamed endpoints; aggressive polling causing rate limits; IP blocked by WAF returning 403; maintenance windows returning 502/503.

Related errors


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

Appendix: source

Thrown at plugin/haisou/haisou.go:347

	}

	// 设置请求头
	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", "application/json, text/plain, */*")
	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", "https://haisou.cc/")

	// 发送HTTP请求(带重试机制)
	resp, err := p.doRequestWithRetry(req, client)
	if err != nil {
		return nil, fmt.Errorf("[%s] %s网盘第%d页请求失败: %w", p.Name(), panType, pageNo, err)
	}
	defer resp.Body.Close()

	// 检查状态码
	if resp.StatusCode != 200 {
		return nil, fmt.Errorf("[%s] %s网盘第%d页返回状态码: %d", p.Name(), panType, pageNo, resp.StatusCode)
	}

	// 读取响应体
	body, err := io.ReadAll(resp.Body)
	if err != nil {
		return nil, fmt.Errorf("[%s] %s网盘第%d页读取响应失败: %w", p.Name(), panType, pageNo, err)
	}

	// 解析响应
	var apiResp SearchAPIResponse
	if err := json.Unmarshal(body, &apiResp); err != nil {
		return nil, fmt.Errorf("[%s] %s网盘第%d页JSON解析失败: %w", p.Name(), panType, pageNo, err)
	}

	// 检查API响应状态
	if apiResp.Code != 0 {
		return nil, fmt.Errorf("[%s] %s网盘第%d页API错误: %s", p.Name(), panType, pageNo, apiResp.Msg)
	}

View on GitHub (pinned to beaa561337)