fish2018/pansou · error

[ ] 搜索返回状态码

Error message

[%s] 搜索返回状态码: %d

What it means

This error is returned by MikuclubPlugin.fetchCategoryPosts when the WordPress search API (https://www.mikuclub.uk/wp-json/utils/v2/post_list) responds with a status code other than 200. The plugin aborts the category search instead of trying to decode a body that is not a valid postListResponse. The numeric code is embedded in the message so the caller can distinguish 403/429/5xx etc.

Solutions

  1. Inspect the numeric status in the message; for 403/429 wait or reduce request rate, for 5xx retry later
  2. Check https://www.mikuclub.uk directly in a browser to confirm the API is up
  3. Update setCommonHeaders (User-Agent/Referer) to match a real browser if protection was added
  4. Re-run the search; the plugin already retries via doRequestWithRetry with exponential backoff

Example fix

// before (caller sees raw error)
results, err := plugin.Search("keyword", nil)
// after (caller classifies status)
results, err := plugin.Search("keyword", nil)
if err != nil {
    if strings.Contains(err.Error(), "状态码: 429") {
        time.Sleep(time.Minute) // back off on rate limit
    }
    return err
}
Defensive patterns

Strategy: try-catch

Validate before calling

// Go: check upstream health before searching
resp, err := http.Head("https://www.mikuclub.uk/")
if err != nil || resp.StatusCode != http.StatusOK {
    // skip search, site is down or blocking
}

Type guard

func isUpstreamStatusError(err error) bool {
    return err != nil && strings.Contains(err.Error(), "搜索返回状态码")
}

Try / catch

results, err := plugin.Search(keyword, nil)
if err != nil {
    if isUpstreamStatusError(err) {
        log.Printf("mikuclub unavailable: %v", err)
        return fallbackResults, nil
    }
    return nil, err
}

Prevention

When it happens

Trigger: fetchCategoryPosts calls doRequestWithRetry and the final HTTP response has StatusCode != http.StatusOK, e.g. the site returns 403 (bot protection / Anubis-like gate), 429 (rate limited), 500 (server error), or 404 after retries exhausted.

Common situations: The mikuclub.uk upstream site is down or under maintenance; anti-scraping protection blocks the plugin's default headers; too-aggressive keyword searching triggers rate limiting; network middleboxes/proxies inject 502/503 responses.

Understand the failure class

Background: "API error: {status}" and "HTTP 401/403/404/429/5xx" errors: non-2xx HTTP responses explained — this error's family across 27 libraries.

Related errors


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

Appendix: source

Thrown at plugin/mikuclub/mikuclub.go:253

	reqURL := fmt.Sprintf("https://www.mikuclub.uk/wp-json/utils/v2/post_list?%s", params.Encode())

	ctx, cancel := context.WithTimeout(context.Background(), searchTimeout)
	defer cancel()

	req, err := http.NewRequestWithContext(ctx, http.MethodGet, reqURL, nil)
	if err != nil {
		return nil, fmt.Errorf("[%s] 创建搜索请求失败: %w", p.Name(), err)
	}
	setCommonHeaders(req, "https://www.mikuclub.uk/")

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

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

	var payload postListResponse
	if err := json.NewDecoder(resp.Body).Decode(&payload); err != nil {
		return nil, fmt.Errorf("[%s] 解析搜索结果失败: %w", p.Name(), err)
	}

	return payload.Posts, nil
}

func (p *MikuclubPlugin) fetchDetailLinks(client *http.Client, postID int64, detailURL string) []model.Link {
	if cached, ok := detailCache.Load(postID); ok {
		if entry, valid := cached.(cacheEntry); valid {
			if time.Now().Before(entry.expiresAt) && len(entry.links) > 0 {
				return entry.links
			}
			detailCache.Delete(postID)
		}

View on GitHub (pinned to beaa561337)