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
- Read the wrapped cause (%w) — it distinguishes DNS, timeout, TLS, and connection errors
- Verify the site domain (BaseURL) is still correct and reachable (curl the URL)
- Increase the 15s context timeout if the site is slow
- Check proxy environment (HTTPS_PROXY) and system DNS
- 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
- Distinguish timeout vs DNS vs TLS by inspecting the wrapped error
- Use a sane timeout (increase 15s if the site is slow)
- Configure proxy env vars if behind a corporate proxy
- Add exponential backoff with a retry cap
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)