fish2018/pansou · error

POST请求失败

Error message

POST请求失败: %w

What it means

postSearchRequest sends the POST via doRequestWithRetry (which follows redirects with a custom CheckRedirect policy). If every attempt fails — network error, DNS failure, timeout, TLS error — the last error is wrapped with this message. The underlying cause is in the wrapped error.

Solutions

  1. Read the wrapped cause (%w) — it distinguishes DNS, timeout, TLS, and connection errors
  2. Verify the site domain (BaseURL) is still correct and reachable (curl the URL)
  3. Increase the 15s context timeout if the site is slow
  4. Check proxy environment (HTTPS_PROXY) and system DNS
  5. Retry later or add longer backoff in doRequestWithRetry

Example fix

// before
resp, err := p.doRequestWithRetry(req, client)
if err != nil {
    return "", fmt.Errorf("POST请求失败: %w", err)
}
// after
var netErr net.Error
resp, err := p.doRequestWithRetry(req, client)
if err != nil {
    if errors.As(err, &netErr) && netErr.Timeout() {
        return "", fmt.Errorf("POST请求超时(15s): %w", err)
    }
    return "", fmt.Errorf("POST请求失败: %w", err)
}
Defensive patterns

Strategy: retry

Validate before calling

// Pre-flight reachability check before the search flow
resp, err := http.Head(BaseURL)
if err != nil || resp.StatusCode >= 500 {
    return fmt.Errorf("site unreachable: %v", err)
}

Try / catch

_, err := plugin.Search(ctx, kw)
var netErr net.Error
if errors.As(err, &netErr) && netErr.Timeout() {
    // retry with longer timeout / later
} else if err != nil {
    // transport failure: check wrapped cause via errors.Unwrap
}

Prevention

When it happens

Trigger: The target site is unreachable: DNS resolution fails, connection refused/times out, TLS handshake fails, the 15s context deadline expires, or a proxy blocks the connection across all retry attempts.

Common situations: Site is down or has changed domain; no internet access / firewall blocks outbound HTTPS; corporate proxy required but unset; the site enforces TLS versions the client rejects; slow site exceeding the 15s timeout.

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/3c3c115047e1cccc. Report an issue: GitHub.

Appendix: source

Thrown at plugin/qupanshe/qupanshe.go:273

				cookies := client.Jar.Cookies(u)
				fmt.Printf("[qupanshe] POST请求将发送 %d 个cookies:\n", len(cookies))
				for i, cookie := range cookies {
					fmt.Printf("  Cookie[%d]: %s=%s\n", i, cookie.Name, cookie.Value)
				}
			}
		}
	}

	// 不自动跟随重定向
	client.CheckRedirect = func(req *http.Request, via []*http.Request) error {
		return http.ErrUseLastResponse
	}
	defer func() { client.CheckRedirect = nil }()

	// 带重试机制的请求
	resp, err := p.doRequestWithRetry(req, client)
	if err != nil {
		return "", fmt.Errorf("POST请求失败: %w", err)
	}
	defer resp.Body.Close()

	if DebugLog {
		fmt.Printf("[qupanshe] POST请求响应: status=%d\n", resp.StatusCode)
		fmt.Printf("[qupanshe] 响应头: %v\n", resp.Header)
	}

	// 从响应头获取Location
	location := resp.Header.Get("Location")
	if DebugLog {
		fmt.Printf("[qupanshe] Location header: %s\n", location)
	}

	// 读取响应体用于调试(非重定向状态码时)
	if resp.StatusCode != 302 && resp.StatusCode != 301 && DebugLog {
		body, readErr := io.ReadAll(resp.Body)
		if readErr == nil {

View on GitHub (pinned to beaa561337)