{"record":{"id":"dc7b81fc53deea52","repo":"fish2018/pansou","slug":"w-dc7b81","errorCode":null,"errorMessage":"请求网站首页失败: %w","messagePattern":"请求网站首页失败: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"plugin/panyq/panyq.go","lineNumber":661,"sourceCode":"\treturn finalIDs, nil\n}\n\n// findPotentialActionIDs 从网站获取潜在的Action ID\nfunc (p *PanyqPlugin) findPotentialActionIDs(client *http.Client) ([]string, error) {\n\t// 请求网站首页\n\treq, err := http.NewRequest(\"GET\", BaseURL, nil)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"创建请求失败: %w\", err)\n\t}\n\t\n\t// 只保留指定的请求头\n\t// req.Header.Set(\"sec-ch-ua\", `\"Not)A;Brand\";v=\"8\", \"Chromium\";v=\"138\", \"Google Chrome\";v=\"138\"`)\n\treq.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\")\n\t\n\t// 发送请求\n\tresp, err := client.Do(req)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"请求网站首页失败: %w\", err)\n\t}\n\tdefer resp.Body.Close()\n\t\n\t// 检查状态码\n\tif resp.StatusCode != http.StatusOK {\n\t\t// 读取响应体以获取服务器返回的具体错误信息\n\t\tbodyBytes, err := io.ReadAll(resp.Body)\n\t\tif err != nil {\n\t\t\t// 如果连响应体都读取失败，则返回状态码错误并附上读取错误\n\t\t\treturn nil, fmt.Errorf(\"请求失败，状态码: %d，且读取响应体错误: %v\", resp.StatusCode, err)\n\t\t}\n\t\t// 将更详细的状态信息 (如 \"404 Not Found\") 和响应体内容一起作为错误返回\n\t\treturn nil, fmt.Errorf(\"请求失败，状态: %s, 详情: %s\", resp.Status, string(bodyBytes))\n\t}\n\n\tbody, err := io.ReadAll(resp.Body)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"读取响应失败: %w\", err)","sourceCodeStart":643,"sourceCodeEnd":679,"githubUrl":"https://github.com/fish2018/pansou/blob/beaa56133755a548ebc51b090b3816e2ae044aa6/plugin/panyq/panyq.go#L643-L679","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Verify basic connectivity to the site domain first: curl -v https://<site-homepage>/ and compare the error.","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.","Check whether the plugin's configured base URL/domain is up to date; the site may have moved to a new domain.","Retry after a delay if it is a transient timeout; consider adding a timeout with retries in the caller (discoverActionIDs).","Inspect the wrapped error with errors.Unwrap / *url.Error to distinguish DNS vs connection vs TLS causes."],"exampleFix":"// before\nresp, err := client.Do(req)\nif err != nil {\n    return nil, fmt.Errorf(\"请求网站首页失败: %w\", err)\n}\n// after\nresp, err := client.Do(req)\nif err != nil {\n    var urlErr *url.Error\n    if errors.As(err, &urlErr) {\n        return nil, fmt.Errorf(\"请求网站首页失败: %w (阶段: %s)\", err, urlErr.Op)\n    }\n    return nil, fmt.Errorf(\"请求网站首页失败: %w\", err)\n}","handlingStrategy":"retry","validationCode":"url := \"https://<site-homepage>/\"\nif u, err := neturl.Parse(url); err != nil || u.Scheme == \"\" || u.Host == \"\" {\n    return fmt.Errorf(\"invalid site URL: %q\", url)\n}\nconn, err := net.DialTimeout(\"tcp\", net.JoinHostPort(u.Hostname(), portOrDefault(u)), 5*time.Second)\nif err != nil {\n    return fmt.Errorf(\"site unreachable before request: %w\", err)\n}\nconn.Close()","typeGuard":"var urlErr *url.Error\nif errors.As(err, &urlErr) {\n    var netErr net.Error\n    if errors.As(urlErr.Err, &netErr) && netErr.Timeout() {\n        // transient — safe to retry\n    }\n}","tryCatchPattern":"resp, err := client.Do(req)\nif err != nil {\n    var urlErr *url.Error\n    if errors.As(err, &urlErr) && isTransient(urlErr) {\n        return retryWithBackoff(req)\n    }\n    return nil, fmt.Errorf(\"请求网站首页失败: %w\", err)\n}","preventionTips":["Pre-check connectivity/DNS to the target domain before invoking discoverActionIDs.","Configure proxy environment variables (HTTPS_PROXY) when the site requires one.","Set a sane client Timeout and implement bounded retries with backoff.","Keep the plugin's base URL/domain updated when the site migrates."],"tags":["network","http","scraping","go"],"backgroundTag":"http-request-failed","analyzedSha":"beaa56133755a548ebc51b090b3816e2ae044aa6","analyzedAt":"2026-09-07T00:31:18.025Z","contentChangedAt":"2026-09-07T00:31:18.025Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}