fish2018/pansou · error
[ ] token请求失败
Error message
[%s] token请求失败: %w
What it means
getToken wraps the error returned by doRequestWithRetry, which performed the token page GET and exhausted its retry loop (connection errors, timeouts, TLS failures). The token could not be fetched from the remote site, so searchImpl cannot proceed. The wrapped cause is the last network error observed across all retries.
Solutions
- Unwrap and log the inner error (%w chain) to see the concrete cause (timeout vs refused vs TLS)
- Verify network reachability: curl the token URL from the same host, check DNS and proxy settings (HTTP_PROXY/HTTPS_PROXY)
- Increase the 30s context timeout or the retry count/backoff in doRequestWithRetry if upstream is slow
- Check whether the site requires cookies/anti-bot handling that redirects in a way the client rejects
Example fix
null
Defensive patterns
Strategy: retry
Validate before calling
// pre-check reachability
conn, err := net.DialTimeout("tcp", host+":443", 5*time.Second)
if err != nil { return fmt.Errorf("unreachable: %w", err) }
conn.Close() Try / catch
if err != nil {
var ne net.Error
if errors.As(err, &ne) && ne.Timeout() {
return retryWithBackoff(ctx)
}
return nil, fmt.Errorf("token fetch failed permanently: %w", err)
} Prevention
- Configure proxy env vars correctly in restricted networks
- Set realistic timeouts; avoid very short deadlines on slow upstreams
- Monitor upstream availability and cache tokens to reduce request volume
When it happens
Trigger: p.doRequestWithRetry(req, client) returns an error — all retry attempts to GET the token page failed (dial errors, context deadline of the 30s timeout, TLS handshake failure, connection reset).
Common situations: Target site blocked/down or geo-restricted; corporate proxy/firewall intercepting; DNS failure; client timeout too short for a slow upstream; missing proxy env config.
Related errors
AI-assisted analysis of fish2018/pansou@beaa561337 (2026-09-07).
Data as JSON: /api/errors/1da029e163ce7e08.
Report an issue: GitHub.
Appendix: source
Thrown at plugin/xys/xys.go:163
defer cancel()
req, err := http.NewRequestWithContext(ctx, "GET", tokenURL, nil)
if err != nil {
return "", fmt.Errorf("[%s] 创建token请求失败: %w", p.Name(), err)
}
// 设置完整的请求头
req.Header.Set("User-Agent", UserAgent)
req.Header.Set("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8")
req.Header.Set("Accept-Language", "zh-CN,zh;q=0.9,en;q=0.8")
req.Header.Set("Connection", "keep-alive")
req.Header.Set("Upgrade-Insecure-Requests", "1")
req.Header.Set("Cache-Control", "max-age=0")
req.Header.Set("Referer", BaseURL+"/")
resp, err := p.doRequestWithRetry(req, client)
if err != nil {
return "", fmt.Errorf("[%s] token请求失败: %w", p.Name(), err)
}
defer resp.Body.Close()
if resp.StatusCode != 200 {
return "", fmt.Errorf("[%s] token请求HTTP状态错误: %d", p.Name(), resp.StatusCode)
}
// 解析HTML提取token
doc, err := goquery.NewDocumentFromReader(resp.Body)
if err != nil {
return "", fmt.Errorf("[%s] 解析token页面HTML失败: %w", p.Name(), err)
}
// 查找script标签中的DToken定义
var token string
doc.Find("script").Each(func(i int, s *goquery.Selection) {
scriptContent := s.Text()
if strings.Contains(scriptContent, "DToken") {View on GitHub (pinned to beaa561337)