{"record":{"id":"108ba0be60ad3e09","repo":"fish2018/pansou","slug":"w-108ba0","errorCode":null,"errorMessage":"获取验证脚本失败: %w","messagePattern":"获取验证脚本失败: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"plugin/qiwei/qiwei.go","lineNumber":359,"sourceCode":"\n\tif lastErr == nil {\n\t\tlastErr = fmt.Errorf(\"[%s] 获取详情失败: %s\", p.Name(), detailURL)\n\t}\n\treturn detailInfo{}, lastErr\n}\n\n// solveVerification completes the site's deterministic slider challenge. The\n// challenge is session-bound, so the caller and this method must share a\n// cookie jar on the same http.Client.\nfunc (p *QiweiPlugin) solveVerification(client *http.Client, pageURL, verifyHTML string) error {\n\tscriptMatch := verificationScriptRegex.FindStringSubmatch(verifyHTML)\n\tif len(scriptMatch) < 2 {\n\t\treturn fmt.Errorf(\"未找到滑动验证脚本\")\n\t}\n\tscriptURL := normalizeURL(pageURL, scriptMatch[1])\n\tjsBody, err := p.fetchBody(client, scriptURL, pageURL, detailTimeout)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"获取验证脚本失败: %w\", err)\n\t}\n\n\ttypeMatch := verificationTypeRegex.FindStringSubmatch(jsBody)\n\tkeyMatch := verificationKeyRegex.FindStringSubmatch(jsBody)\n\tvalueMatch := verificationValueRegex.FindStringSubmatch(jsBody)\n\tif len(typeMatch) < 2 || len(keyMatch) < 2 || len(valueMatch) < 2 {\n\t\treturn fmt.Errorf(\"验证脚本参数不完整\")\n\t}\n\n\tencodedValue := md5StringToHex(valueMatch[1])\n\tendpointPath := \"/a20be899_96a6_40b2_88ba_32f1f75f1552_yanzheng_huadong.php\"\n\tif endpointMatch := verificationEndpointRegex.FindStringSubmatch(jsBody); len(endpointMatch) > 1 {\n\t\tendpointPath = \"/\" + endpointMatch[1]\n\t}\n\tparsedPage, err := url.Parse(pageURL)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"验证页面地址无效: %w\", err)\n\t}","sourceCodeStart":341,"sourceCodeEnd":377,"githubUrl":"https://github.com/fish2018/pansou/blob/beaa56133755a548ebc51b090b3816e2ae044aa6/plugin/qiwei/qiwei.go#L341-L377","documentation":"After locating the verification script URL, solveVerification downloads the JS file with fetchBody. If that HTTP fetch fails (network error, timeout, non-OK status handled by fetchBody), the error is wrapped with this message and returned, aborting the verification solve. The %w wrapping preserves the underlying network/HTTP error for errors.Is/As inspection.","triggerScenarios":"In solveVerification, p.fetchBody(client, scriptURL, pageURL, detailTimeout) returns a non-nil error while downloading the verification challenge JS from the host serving the slider script.","commonSituations":"The script host blocks datacenter IPs or requires a Referer/cookie the client isn't sending; scriptURL is relative and normalizeURL produced a wrong absolute URL; detailTimeout is too short for a slow script CDN; the site moved or removed the verification script (404).","solutions":["Print/check the wrapped cause (errors.Unwrap) to see if it's a timeout, DNS failure, or HTTP status, and fix accordingly.","Verify normalizeURL(pageURL, scriptMatch[1]) yields the correct absolute script URL — a bad base or relative path yields a 404.","Ensure the request carries the site's cookies/Referer (same client with cookie jar) since the script host may reject unauthenticated fetches.","Increase detailTimeout if the script host is slow, or retry the fetch with backoff.","Check whether the script URL changed on the site and update the fetch or add a fallback mirror path."],"exampleFix":"// before\njsBody, err := p.fetchBody(client, scriptURL, pageURL, detailTimeout)\nif err != nil {\n    return fmt.Errorf(\"获取验证脚本失败: %w\", err)\n}\n// after\njsBody, err := p.fetchBody(client, scriptURL, pageURL, detailTimeout)\nif err != nil {\n    return fmt.Errorf(\"获取验证脚本失败 (url=%s): %w\", scriptURL, err) // include URL for diagnosis\n}","handlingStrategy":"retry","validationCode":"// sanity-check the absolute script URL before fetching\nabs := normalizeURL(pageURL, scriptMatch[1])\nif u, err := neturl.Parse(abs); err != nil || u.Host == \"\" {\n    return fmt.Errorf(\"invalid verification script URL derived from %s\", pageURL)\n}","typeGuard":"func isScriptFetchErr(err error) bool {\n    var ne net.Error\n    return err != nil && (errors.As(err, &ne) || strings.Contains(err.Error(), \"获取验证脚本失败\"))\n}","tryCatchPattern":"if err := plugin.SolveVerification(client, pageURL, body); err != nil {\n    var netErr net.Error\n    if errors.As(err, &netErr) && netErr.Timeout() {\n        // transient: retry once with a longer timeout\n        time.Sleep(time.Second)\n        return plugin.SolveVerification(client, pageURL, body)\n    }\n    return err\n}","preventionTips":["Set detailTimeout generously for script CDN fetches, with one retry on timeout.","Log scriptURL on failure to distinguish bad URL construction from network issues.","Ensure cookies/Referer from the challenge page are sent when fetching the script.","Verify normalizeURL output in tests for relative script paths (e.g. /static/verify.js).","Watch the wrapped cause for 403/404 to detect bot-blocking or script relocation early."],"tags":["network","http","captcha","script-fetch","timeout"],"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"}