fish2018/pansou · error

搜索响应状态码异常

Error message

搜索响应状态码异常: %d

What it means

The xiaozhang plugin's searchImpl got a valid HTTP response from the search endpoint, but the status code was not 200. The plugin only treats HTTP 200 as a successful search result page; anything else (3xx followed into an unexpected page, 4xx anti-bot block, 5xx server error) triggers this error with the numeric status embedded. It indicates the upstream site responded but refused or failed the search request.

Solutions

  1. Log the full status code and response body snippet to identify which non-200 class is returned.
  2. For 403/429, update request headers (User-Agent, cookies) in setRequestHeaders to look less like a bot, or add rate limiting/backoff.
  3. For 404, verify SearchPath against the current site layout and update the constant.
  4. For 5xx, retry with exponential backoff — the upstream may be temporarily down.
  5. Check whether the site now requires cookies/JS challenge (Cloudflare etc.) and handle accordingly.

Example fix

// before
if resp.StatusCode != http.StatusOK {
    return nil, fmt.Errorf("搜索响应状态码异常: %d", resp.StatusCode)
}
// after
if resp.StatusCode != http.StatusOK {
    body, _ := io.ReadAll(io.LimitReader(resp.Body, 512))
    return nil, fmt.Errorf("搜索响应状态码异常: %d, body: %s", resp.StatusCode, string(body))
}
Defensive patterns

Strategy: retry

Validate before calling

// Go: probe the endpoint and inspect status before trusting search results
resp, err := http.Head(searchURL)
if err != nil {
    return fmt.Errorf("probe failed: %w", err)
}
resp.Body.Close()
if resp.StatusCode != http.StatusOK {
    return fmt.Errorf("upstream unhealthy, status %d", resp.StatusCode)
}

Type guard

// Go: distinguish rate-limit/blocks from server errors
func classifyStatus(code int) string {
    switch {
    case code == 200:
        return "ok"
    case code == 429 || code == 403:
        return "blocked"
    case code >= 500:
        return "server-error"
    default:
        return "other"
    }
}

Try / catch

results, err := plugin.Search(keyword, ext)
if err != nil {
    var statusErr *statusCodeError // if plugin exposes a typed error; otherwise parse message
    if strings.Contains(err.Error(), "状态码异常") {
        // non-200: back off then retry; if still blocked, skip this source
        time.Sleep(backoff)
        results, err = plugin.Search(keyword, ext)
    }
    if err != nil {
        log.Printf("xinjuc/xiaozhang search skipped: %v", err)
    }
}

Prevention

When it happens

Trigger: Calling Search on the xiaozhang plugin when the search URL returns any non-200 status: 403/429 from anti-crawler WAF, 404 after a site path change, 500/502/503 server errors, or a redirect chain that lands on a non-200 page (redirects are followed since followRedirect=true).

Common situations: The site deployed anti-bot protection and starts serving 403/429 to the plugin's User-Agent; the site restructured and SearchPath now 404s; the site is rate-limiting after frequent scraping; or a CDN serves 5xx during an outage.

Related errors


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

Appendix: source

Thrown at plugin/xiaozhang/xiaozhang.go:151

// searchImpl 实际的搜索实现
func (p *XiaozhangPlugin) searchImpl(client *http.Client, keyword string, ext map[string]interface{}) ([]model.SearchResult, error) {
	searchURL := fmt.Sprintf("%s%s?keyword=%s", BaseURL, SearchPath, url.QueryEscape(keyword))
	
	if p.debugMode {
		log.Printf("[Xiaozhang] 开始搜索: %s", keyword)
		log.Printf("[Xiaozhang] 搜索URL: %s", searchURL)
	}
	
	// 发送搜索请求
	resp, err := p.doRequest(client, searchURL, BaseURL, true)
	if err != nil {
		return nil, fmt.Errorf("发送搜索请求失败: %w", err)
	}
	defer resp.Body.Close()
	
	if resp.StatusCode != http.StatusOK {
		return nil, fmt.Errorf("搜索响应状态码异常: %d", resp.StatusCode)
	}
	
	// 处理响应体(可能是gzip压缩的)
	var reader io.Reader = resp.Body
	
	// 检查Content-Encoding
	contentEncoding := resp.Header.Get("Content-Encoding")
	if p.debugMode {
		log.Printf("[Xiaozhang] Content-Encoding: %s", contentEncoding)
		log.Printf("[Xiaozhang] Content-Type: %s", resp.Header.Get("Content-Type"))
	}
	
	// 如果是gzip压缩,手动解压
	if contentEncoding == "gzip" {
		gzReader, err := gzip.NewReader(resp.Body)
		if err != nil {
			return nil, fmt.Errorf("创建gzip reader失败: %w", err)
		}

View on GitHub (pinned to beaa561337)