fish2018/pansou · error

期望302重定向,但得到状态码

Error message

期望302重定向,但得到状态码: %d

What it means

ClxiongPlugin.getSearchID expected the search POST to respond with an HTTP 301/302 redirect (the searchid is extracted from the Location header) but the server returned some other status. This breaks the plugin's core assumption about the site's two-step search flow. Common offending codes: 200 (site changed flow or serves an HTML challenge), 403 (blocked), 429 (rate limited), 5xx (server error).

Solutions

  1. Log the response body alongside the status code to see whether it's a CAPTCHA/challenge, rate-limit notice, or a changed flow.
  2. If 403: update User-Agent/cookies/headers in getSearchID to mimic a browser.
  3. If 429: implement backoff and reduce search frequency; honor Retry-After.
  4. If 200 with HTML: the site changed its search flow — update getSearchID to extract the searchid from the new response (page HTML or a JSON API) instead of expecting a redirect.
  5. If 5xx: retry later; consider adding 5xx handling to the retry loop.

Example fix

// before
if resp.StatusCode != 302 && resp.StatusCode != 301 {
    return "", fmt.Errorf("期望302重定向,但得到状态码: %d", resp.StatusCode)
}
// after
if resp.StatusCode != 302 && resp.StatusCode != 301 {
    snippet := ""
    if b, e := io.ReadAll(io.LimitReader(resp.Body, 512)); e == nil { snippet = string(b) }
    return "", fmt.Errorf("期望302重定向,但得到状态码: %d, body: %q", resp.StatusCode, snippet)
}
Defensive patterns

Strategy: fallback

Validate before calling

// pre-flight: confirm the endpoint still redirects
func stillRedirects(client *http.Client, postURL string, form url.Values) bool {
    client.CheckRedirect = func(req *http.Request, via []*http.Request) error { return http.ErrUseLastResponse }
    resp, err := client.PostForm(postURL, form)
    if err != nil { return false }
    defer resp.Body.Close()
    return resp.StatusCode == 301 || resp.StatusCode == 302
}

Try / catch

searchID, err := p.getSearchID(keyword)
if err != nil {
    if strings.Contains(err.Error(), "期望302重定向") {
        // site no longer redirects: switch to alternate extraction path
        return p.searchViaHTMLFallback(keyword)
    }
    return nil, err
}

Prevention

When it happens

Trigger: getSearchID's POST (after its retry loop succeeded in getting any response) receives resp.StatusCode not in {301, 302}; the function immediately returns "期望302重定向,但得到状态码: %d" to SearchWithResult, failing the whole search.

Common situations: clxiong deployed an anti-bot page or JS challenge answering 200 instead of redirecting; the client is rate limited (429) after rapid searches; blocked User-Agent yields 403; the site's search endpoint changed and now returns 404 or 200 with different semantics; server-side errors (500/503).

Related errors


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

Appendix: source

Thrown at plugin/clxiong/clxiong.go:157

		if lastErr == nil && (resp.StatusCode == 302 || resp.StatusCode == 301) {
			break
		}
		if resp != nil {
			resp.Body.Close()
		}
		if i < MaxRetries-1 {
			time.Sleep(RetryDelay)
		}
	}

	if lastErr != nil {
		return "", lastErr
	}
	defer resp.Body.Close()

	// 检查重定向响应
	if resp.StatusCode != 302 && resp.StatusCode != 301 {
		return "", fmt.Errorf("期望302重定向,但得到状态码: %d", resp.StatusCode)
	}

	// 从Location头部提取searchid
	location := resp.Header.Get("Location")
	if location == "" {
		return "", fmt.Errorf("重定向响应中没有Location头部")
	}

	// 解析searchid
	searchID := p.extractSearchIDFromLocation(location)
	if searchID == "" {
		return "", fmt.Errorf("无法从Location中提取searchid: %s", location)
	}

	if p.debugMode {
		log.Printf("[CLXIONG] 获取到searchid: %s", searchID)
	}

View on GitHub (pinned to beaa561337)