{"record":{"id":"f55faf4abdba388e","repo":"jackwener/OpenCLI","slug":"http-error-f55faf","errorCode":"HTTP_ERROR","errorMessage":"ths hot-rank failed: HTTP ${resp.status}","messagePattern":"ths hot-rank failed: HTTP (.+?)","errorType":"http","errorClass":"CliError","httpStatus":null,"severity":"error","filePath":"clis/ths/hot-rank.js","lineNumber":43,"sourceCode":"    access: 'read',\n  description: '同花顺热股榜',\n  domain: 'dq.10jqka.com.cn',\n  strategy: Strategy.PUBLIC,\n  browser: false,\n  args: [\n    { name: 'limit', type: 'int', default: 20, help: '返回数量' },\n  ],\n  columns: ['rank', 'name', 'changePercent', 'heat', 'tags'],\n  func: async (args) => {\n    const limit = parseLimit(args.limit);\n    const resp = await fetch(THS_HOT_API_URL, {\n      headers: {\n        'Accept': 'application/json,text/plain,*/*',\n        'User-Agent': 'Mozilla/5.0',\n        'Referer': 'https://eq.10jqka.com.cn/',\n      },\n    });\n    if (!resp.ok) throw new CliError('HTTP_ERROR', `ths hot-rank failed: HTTP ${resp.status}`);\n    const payload = await resp.json();\n    const stocks = Array.isArray(payload?.data?.stock_list) ? payload.data.stock_list : [];\n    if (stocks.length === 0) throw new CliError('NO_DATA', 'ths hot-rank API returned no stock data');\n\n    return stocks.slice(0, limit).map((stock, index) => ({\n      rank: stock.order ?? index + 1,\n      name: stock.name ?? '',\n      changePercent: stock.rise_and_fall ?? '',\n      heat: stock.rate ?? '',\n      tags: tagsFromStock(stock),\n    }));\n  },\n});\n\nexport const __test__ = {\n  THS_HOT_API_URL,\n  parseLimit,\n  tagsFromStock,","sourceCodeStart":25,"sourceCodeEnd":61,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/ths/hot-rank.js#L25-L61","documentation":"The ths hot-rank command fetches the 10jqka (同花顺) hot-stock ranking JSON endpoint and checks resp.ok. Any non-2xx HTTP status (403 anti-bot, 404, 5xx) throws CliError HTTP_ERROR with the status embedded in the message.","triggerScenarios":"HTTP fetch to the eq.10jqka.com.cn hot-rank API returning non-ok status: server error, rate-limit/WAF 403 due to missing cookies or blocked UA, or endpoint path change.","commonSituations":"10jqka WAF blocking requests without browser cookies; temporary 5xx outage; ISP/region blocks; API endpoint renamed after site redesign.","solutions":["Retry after a short backoff (transient 5xx/rate limit)","Send browser-like headers including a real User-Agent and any required 10jqka cookies","Check the endpoint URL is still valid in a browser and update clis/ths/hot-rank.js if the API moved","Route through a proxy/egress IP not blocked by 10jqka if 403 persists"],"exampleFix":"// before\nconst resp = await fetch(url, { headers: { 'User-Agent': 'Mozilla/5.0' } });\n// after\nconst resp = await fetch(url, { headers: browserHeaders });\nif (!resp.ok) throw new CliError('HTTP_ERROR', `ths hot-rank failed: HTTP ${resp.status}`);\n// add retry with backoff on 429/5xx before giving up","handlingStrategy":"retry","validationCode":"// preflight: endpoint reachability\nconst head = await fetch(url, { method: 'GET', headers: { 'Accept': 'application/json' } });\nif (!head.ok) console.warn(`ths endpoint unhealthy: HTTP ${head.status}`);","typeGuard":null,"tryCatchPattern":"try {\n  const stocks = await thsHotRank({ limit });\n} catch (e) {\n  if (e?.code === 'HTTP_ERROR') {\n    await sleep(2000);\n    return thsHotRank({ limit }); // retry once with backoff\n  }\n  throw e;\n}","preventionTips":["Send realistic browser headers (User-Agent, Referer, cookies) to avoid WAF 403s","Add exponential backoff retry for 429/5xx responses","Monitor the 10jqka endpoint for URL/schema changes","Avoid hammering the API from flagged/datacenter IPs"],"tags":["http","network","ths","api"],"backgroundTag":"http-request-failed","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}