{"record":{"id":"efb7ed180cace3d2","repo":"jackwener/OpenCLI","slug":"json-efb7ed","errorCode":null,"errorMessage":"响应不是有效 JSON","messagePattern":"响应不是有效 JSON","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/xueqiu/utils.js","lineNumber":53,"sourceCode":" */\nexport async function fetchXueqiuJson(page, url) {\n    const result = await page.evaluate(`(async () => {\n    const res = await fetch(${JSON.stringify(url)}, { credentials: 'include' });\n    if (!res.ok) return { __xqErr: res.status };\n    try {\n      return await res.json();\n    } catch {\n      return { __xqErr: 'parse' };\n    }\n  })()`);\n    const r = result;\n    if (r?.__xqErr !== undefined) {\n        const code = r.__xqErr;\n        if (code === 401 || code === 403) {\n            throw new AuthRequiredError('xueqiu.com', '未登录或登录已过期');\n        }\n        if (code === 'parse') {\n            throw new CommandExecutionError('响应不是有效 JSON', '可能触发了风控，请检查登录状态或稍后重试');\n        }\n        throw new CommandExecutionError(`HTTP ${code}`, '请检查网络连接或登录状态');\n    }\n    return result;\n}\n","sourceCodeStart":35,"sourceCodeEnd":59,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/xueqiu/utils.js#L35-L59","documentation":"fetchXueqiuJson tries res.json() inside the browser context; when the body cannot be parsed as JSON it returns {__xqErr:'parse'} and the wrapper throws CommandExecutionError('响应不是有效 JSON'). The library throws this because a non-JSON body almost always means xueqiu served an anti-bot/risk-control HTML page instead of the API payload, so the result would be unusable garbage if passed through.","triggerScenarios":"The fetch to a stock.xueqiu.com v5 endpoint returns 200 but with an HTML body (risk-control challenge, login interstitial, or WAF block page) so res.json() throws inside page.evaluate.","commonSituations":"Aggressive polling triggers xueqiu's anti-crawler; logged-out traffic redirected to an HTML page; CDN/WAF returns an error page with 200; network middleware injects HTML.","solutions":["Check login status in the browser and re-authenticate if needed","Wait and retry later — risk control blocks are usually temporary","Reduce request rate / add delays between xueqiu calls","Verify the URL is a valid xueqiu JSON API endpoint"],"exampleFix":"// before (tight loop triggers risk control)\nfor (const pid of pids) await fetchXueqiuJson(page, url(pid));\n// after (throttle + retry on parse failure)\ntry {\n  const d = await fetchXueqiuJson(page, url(pid));\n} catch (e) {\n  if (String(e.message).includes('JSON')) await sleep(5000);\n}","handlingStrategy":"retry","validationCode":"const html = await page.content();\nif (html.includes('verify') || html.includes('captcha')) await sleep(10000); // risk-control page detected","typeGuard":"function isJsonLike(v) { return v != null && typeof v === 'object' && v.__xqErr === undefined; }","tryCatchPattern":"try {\n  const d = await fetchXueqiuJson(page, url);\n} catch (e) {\n  if (String(e.message).includes('响应不是有效 JSON')) {\n    await sleep(5000); // wait out risk control, then retry once\n    return fetchXueqiuJson(page, url);\n  }\n  throw e;\n}","preventionTips":["Throttle xueqiu requests (add delays between calls)","Keep the session logged in — anonymous traffic is more likely to get HTML challenge pages","Retry with exponential backoff on parse failures","Check page content for captcha/verify markers before concluding the API is broken"],"tags":["xueqiu","json-parse","anti-bot","risk-control"],"backgroundTag":"invalid-json-response","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}