fish2018/pansou · error

请求网站首页失败

Error message

请求网站首页失败: %w

What it means

findPotentialActionIDs fetches the target site's homepage with an HTTP client to discover Next.js action IDs. When the HTTP transport itself fails (DNS resolution failure, connection refused/reset, TLS handshake error, timeout), the underlying error is wrapped with this message via %w so callers can unwrap it with errors.Is/As. It means the site could not be reached at all — no response was received.

Solutions

  1. Verify basic connectivity to the site domain first: curl -v https://<site-homepage>/ and compare the error.
  2. Check proxy/VPN requirements — set HTTP_PROXY/HTTPS_PROXY or configure the client's Transport with a Proxy function if the site is unreachable directly.
  3. Check whether the plugin's configured base URL/domain is up to date; the site may have moved to a new domain.
  4. Retry after a delay if it is a transient timeout; consider adding a timeout with retries in the caller (discoverActionIDs).
  5. Inspect the wrapped error with errors.Unwrap / *url.Error to distinguish DNS vs connection vs TLS causes.

Example fix

// before
resp, err := client.Do(req)
if err != nil {
    return nil, fmt.Errorf("请求网站首页失败: %w", err)
}
// after
resp, err := client.Do(req)
if err != nil {
    var urlErr *url.Error
    if errors.As(err, &urlErr) {
        return nil, fmt.Errorf("请求网站首页失败: %w (阶段: %s)", err, urlErr.Op)
    }
    return nil, fmt.Errorf("请求网站首页失败: %w", err)
}
Defensive patterns

Strategy: retry

Validate before calling

url := "https://<site-homepage>/"
if u, err := neturl.Parse(url); err != nil || u.Scheme == "" || u.Host == "" {
    return fmt.Errorf("invalid site URL: %q", url)
}
conn, err := net.DialTimeout("tcp", net.JoinHostPort(u.Hostname(), portOrDefault(u)), 5*time.Second)
if err != nil {
    return fmt.Errorf("site unreachable before request: %w", err)
}
conn.Close()

Type guard

var urlErr *url.Error
if errors.As(err, &urlErr) {
    var netErr net.Error
    if errors.As(urlErr.Err, &netErr) && netErr.Timeout() {
        // transient — safe to retry
    }
}

Try / catch

resp, err := client.Do(req)
if err != nil {
    var urlErr *url.Error
    if errors.As(err, &urlErr) && isTransient(urlErr) {
        return retryWithBackoff(req)
    }
    return nil, fmt.Errorf("请求网站首页失败: %w", err)
}

Prevention

When it happens

Trigger: client.Do(req) returns a non-nil error inside findPotentialActionIDs (invoked via discoverActionIDs): network unreachable, DNS failure for the site domain, connection refused by the server/proxy, TLS certificate error, or request context timeout.

Common situations: The panyq site domain changed or is blocked by the user's firewall/GFW; the machine has no internet access; a corporate proxy is required but not configured; the site temporarily went offline; DNS pollution returning NXDOMAIN.

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

Appendix: source

Thrown at plugin/panyq/panyq.go:661

	return finalIDs, nil
}

// findPotentialActionIDs 从网站获取潜在的Action ID
func (p *PanyqPlugin) findPotentialActionIDs(client *http.Client) ([]string, error) {
	// 请求网站首页
	req, err := http.NewRequest("GET", BaseURL, nil)
	if err != nil {
		return nil, fmt.Errorf("创建请求失败: %w", err)
	}
	
	// 只保留指定的请求头
	// req.Header.Set("sec-ch-ua", `"Not)A;Brand";v="8", "Chromium";v="138", "Google Chrome";v="138"`)
	req.Header.Set("User-Agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36")
	
	// 发送请求
	resp, err := client.Do(req)
	if err != nil {
		return nil, fmt.Errorf("请求网站首页失败: %w", err)
	}
	defer resp.Body.Close()
	
	// 检查状态码
	if resp.StatusCode != http.StatusOK {
		// 读取响应体以获取服务器返回的具体错误信息
		bodyBytes, err := io.ReadAll(resp.Body)
		if err != nil {
			// 如果连响应体都读取失败,则返回状态码错误并附上读取错误
			return nil, fmt.Errorf("请求失败,状态码: %d,且读取响应体错误: %v", resp.StatusCode, err)
		}
		// 将更详细的状态信息 (如 "404 Not Found") 和响应体内容一起作为错误返回
		return nil, fmt.Errorf("请求失败,状态: %s, 详情: %s", resp.Status, string(bodyBytes))
	}

	body, err := io.ReadAll(resp.Body)
	if err != nil {
		return nil, fmt.Errorf("读取响应失败: %w", err)

View on GitHub (pinned to beaa561337)