fish2018/pansou · error

[ ] Cloudflare 请求客户端未初始化

Error message

[%s] Cloudflare 请求客户端未初始化

What it means

The Diduan plugin relies on a cloudscraper client (p.scraper) initialized during plugin setup to bypass Cloudflare. searchImpl returns this error immediately when p.scraper is nil, meaning the Cloudflare-capable client was never constructed successfully.

Solutions

  1. Check plugin startup logs for the cloudscraper initialization error and fix the root cause.
  2. Ensure the plugin's Init/constructor that creates p.scraper runs before any search is issued.
  3. Validate scraper-related configuration (proxy, browser emulation options) is present and valid.
  4. Add a startup health check that fails fast if p.scraper is nil instead of failing at search time.

Example fix

// before
p := &DiduanPlugin{}
results, err := p.Search(keyword) // fails: scraper nil
// after
p := NewDiduanPlugin()
if err := p.Init(cfg); err != nil { log.Fatalf("init: %v", err) }
results, err := p.Search(keyword)
Defensive patterns

Strategy: validation

Validate before calling

if p.scraper == nil {
    return errors.New("diduan plugin not initialized: scraper is nil")
}
// safe to search

Try / catch

if err != nil {
    if strings.Contains(err.Error(), "未初始化") {
        return fmt.Errorf("re-init plugin before searching: %w", err)
    }
    return err
}

Prevention

When it happens

Trigger: p.searchImpl is invoked (via AsyncSearchWithResult) but plugin initialization failed or was skipped, leaving p.scraper nil — e.g. the cloudscraper constructor returned an error that was ignored or logged only.

Common situations: Missing dependencies or options for initializing the scraper at startup; plugin constructed directly in tests without calling the init routine; an earlier init failure (bad proxy config, missing browser fingerprint data) left the scraper unset.

Related errors


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

Appendix: source

Thrown at plugin/diduan/diduan.go:130

// Search 搜索接口
func (p *DiduanPlugin) Search(keyword string, ext map[string]interface{}) ([]model.SearchResult, error) {
	result, err := p.SearchWithResult(keyword, ext)
	if err != nil {
		return nil, err
	}
	return result.Results, nil
}

// SearchWithResult 使用 BaseAsyncPlugin 的缓存和后台刷新能力。
func (p *DiduanPlugin) SearchWithResult(keyword string, ext map[string]interface{}) (model.PluginSearchResult, error) {
	return p.AsyncSearchWithResult(keyword, p.searchImpl, p.MainCacheKey, ext)
}

// searchImpl 搜索实现
func (p *DiduanPlugin) searchImpl(client *http.Client, keyword string, ext map[string]interface{}) ([]model.SearchResult, error) {
	if p.scraper == nil {
		return nil, fmt.Errorf("[%s] Cloudflare 请求客户端未初始化", p.Name())
	}
	if p.debugMode {
		log.Printf("[DIDUAN] 开始搜索: %s", keyword)
	}

	// 第一步:执行搜索获取结果列表
	searchResults, err := p.executeSearch(keyword)
	if err != nil {
		return nil, fmt.Errorf("[%s] 执行搜索失败: %w", p.Name(), err)
	}

	if p.debugMode {
		log.Printf("[DIDUAN] 搜索获取到 %d 个结果", len(searchResults))
	}

	// 第二步:并发获取详情页链接
	finalResults := p.fetchDetailLinks(searchResults, keyword)

View on GitHub (pinned to beaa561337)