fish2018/pansou · error

[ ] 创建token请求失败

Error message

[%s] 创建token请求失败: %w

What it means

getToken wraps the error from http.NewRequestWithContext when building the GET request to the site's token page. The plugin needs a DToken scraped from an HTML page before it can search; if the request object itself cannot be constructed (bad URL, invalid method/ctx combination) the token fetch is aborted and the wrapped error is returned up through searchImpl. This is a pre-flight construction failure, not a network failure.

Solutions

  1. Print/log the tokenURL value and validate it with url.Parse before calling http.NewRequestWithContext
  2. Check that BaseURL/tokenURL constants in plugin/xys/xys.go are intact and correctly formatted (https://host/path)
  3. If the URL is derived from user input, sanitize/escape it (strings.ContainsAny for control chars, url.QueryEscape)

Example fix

// before
req, err := http.NewRequestWithContext(ctx, "GET", tokenURL, nil)
if err != nil {
    return "", fmt.Errorf("[%s] 创建token请求失败: %w", p.Name(), err)
}
// after
u, perr := url.Parse(tokenURL)
if perr != nil {
    return "", fmt.Errorf("[%s] invalid token URL %q: %w", p.Name(), tokenURL, perr)
}
req, err := http.NewRequestWithContext(ctx, "GET", u.String(), nil)
if err != nil {
    return "", fmt.Errorf("[%s] 创建token请求失败: %w", p.Name(), err)
}
Defensive patterns

Strategy: validation

Validate before calling

u, err := url.Parse(tokenURL)
if err != nil || u.Scheme == "" || u.Host == "" {
    return fmt.Errorf("invalid token URL: %v", err)
}

Try / catch

if err != nil {
    var ue *url.Error
    if errors.As(err, &ue) {
        log.Printf("bad token URL %q: %v", ue.URL, ue.Err)
    }
    return fallbackSearch()
}

Prevention

When it happens

Trigger: http.NewRequestWithContext(ctx, "GET", tokenURL, nil) returns a non-nil err — in practice a malformed or unparseable tokenURL (e.g. control characters, unparseable scheme) since method/ctx are constants here.

Common situations: BaseURL or token URL constant corrupted by an edit or config substitution; URL built with unescaped user input containing newlines/control chars; Go stdlib rejecting an invalid URL string.

Understand the failure class

Background: "Invalid URL" / "URL cannot be empty": fix the malformed or missing URL behind request-construction failures — this error's family across 50 libraries.

Related errors


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

Appendix: source

Thrown at plugin/xys/xys.go:149

				if p.debugMode {
					log.Printf("[XYS] 使用缓存的token")
				}
				return tokenCache.Token, nil
			}
		}
	}

	// 构建请求URL
	tokenURL := fmt.Sprintf("%s%s?wd=%s&mode=undefined&stype=undefined",
		BaseURL, TokenPath, url.QueryEscape(keyword))

	// 创建带超时的上下文
	ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
	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 {

View on GitHub (pinned to beaa561337)