fish2018/pansou · error

[ ] 获取接口配置失败

Error message

[%s] 获取接口配置失败: %w

What it means

fetchConfig calls GET {apiBaseURL}/test via requestJSON to obtain the API configuration envelope; if that request fails at the transport/decoding level, the error is wrapped as 获取接口配置失败. This is a bootstrap step — search cannot proceed without the config (e.g. a key extracted from the XOR-decoded Data).

Solutions

  1. Verify apiBaseURL is correct and reachable (curl {apiBaseURL}/test).
  2. Inspect the wrapped error from requestJSON for connection vs decode details.
  3. Update the plugin/config if the upstream endpoint changed.
  4. Add a timeout and retry for transient network failures.

Example fix

// before
if err := p.requestJSON(ctx, client, http.MethodGet, p.apiBaseURL+"/test", nil, &response); err != nil {
    return apiConfig{}, fmt.Errorf("[%s] 获取接口配置失败: %w", p.Name(), err)
}
// after
endpoint := strings.TrimRight(p.apiBaseURL, "/") + "/test"
if err := p.requestJSON(ctx, client, http.MethodGet, endpoint, nil, &response); err != nil {
    return apiConfig{}, fmt.Errorf("[%s] 获取接口配置失败: %w (endpoint: %s)", p.Name(), err, endpoint)
}
Defensive patterns

Strategy: try-catch

Validate before calling

// Go: validate config before calling
if p.apiBaseURL == "" {
    return fmt.Errorf("apiBaseURL is not configured")
}
u, err := url.Parse(p.apiBaseURL)
if err != nil || u.Scheme == "" || u.Host == "" {
    return fmt.Errorf("invalid apiBaseURL: %q", p.apiBaseURL)
}

Try / catch

cfg, err := fetchConfig(ctx, client)
if err != nil {
    if strings.Contains(err.Error(), "获取接口配置失败") {
        log.Printf("Yingso config endpoint unreachable, retrying: %v", err)
        return fetchConfigWithRetry(ctx, client, 3)
    }
    return err
}

Prevention

When it happens

Trigger: The GET to p.apiBaseURL+"/test" failed: connection refused/timeout, non-2xx status, or the response body could not be decoded into apiEnvelope[string] by requestJSON.

Common situations: Wrong or outdated apiBaseURL in the plugin config; upstream /test endpoint moved or was removed; firewall/proxy blocks the request; upstream serving an HTML error page instead of the expected envelope.

Understand the failure class

Background: 'Something went wrong' / 'Request failed (500)' / 'HTTP error! status: 404' — what failed HTTP requests actually mean and how to find the real cause — this error's family across 28 libraries.

Related errors


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

Appendix: source

Thrown at plugin/yingso/yingso.go:193

	for index, result := range resolved {
		if !valid[index] || len(result.Links) == 0 {
			continue
		}
		linkKey := result.Links[0].URL + "\x00" + result.Links[0].Password
		if _, exists := seen[linkKey]; exists {
			continue
		}
		seen[linkKey] = struct{}{}
		results = append(results, result)
	}

	return plugin.FilterResultsByKeyword(results, keyword), nil
}

func (p *YingsoPlugin) fetchConfig(ctx context.Context, client *http.Client) (apiConfig, error) {
	var response apiEnvelope[string]
	if err := p.requestJSON(ctx, client, http.MethodGet, p.apiBaseURL+"/test", nil, &response); err != nil {
		return apiConfig{}, fmt.Errorf("[%s] 获取接口配置失败: %w", p.Name(), err)
	}
	if response.Code != http.StatusOK || response.Data == "" {
		return apiConfig{}, fmt.Errorf("[%s] 接口配置异常: code=%d msg=%s", p.Name(), response.Code, response.Msg)
	}

	decoded := xorUTF16(response.Data, bootstrapKey)
	var config apiConfig
	if err := jsonutil.UnmarshalString(decoded, &config); err != nil {
		return apiConfig{}, fmt.Errorf("[%s] 解析接口配置失败: %w", p.Name(), err)
	}
	if config.URLVersion == "" || config.UserID == "" || config.Start < 0 || config.End <= config.Start || config.End > 24 {
		return apiConfig{}, fmt.Errorf("[%s] 接口配置缺少必要字段", p.Name())
	}
	return config, nil
}

func (p *YingsoPlugin) search(ctx context.Context, client *http.Client, config apiConfig, keyword string) ([]searchItem, error) {
	payload := searchPayload{

View on GitHub (pinned to beaa561337)