jackwener/OpenCLI · error · CliError
HTTP_ERROR
HTTP_ERROR
Error message
`northbound failed: HTTP ${resp.status}` What it means
After fetching https://push2.eastmoney.com/api/qt/kamtbs.rtmin/get, northbound.js checks resp.ok and throws this CliError with code HTTP_ERROR if the response status is not 2xx. It wraps the upstream HTTP status in the message so the developer knows the eastmoney endpoint rejected or failed the request.
Source
Thrown at clis/eastmoney/northbound.js:36
args: [
{ name: 'direction', type: 'string', default: 'north', help: '方向:north (北向,即外资买A) / south (南向,即内地买港)' },
{ name: 'limit', type: 'int', default: 10, help: '返回最近 N 分钟' },
],
columns: ['time', 'cumulativeNetYi', 'minuteNetYi', 'totalNetYi'],
func: async (args) => {
const dir = String(args.direction ?? 'north').toLowerCase();
if (!['north', 'south', 'n', 's'].includes(dir)) {
throw new CliError('INVALID_ARGUMENT', `Unknown direction "${dir}". Valid: north / south`);
}
const limit = Math.max(1, Math.min(Number(args.limit) || 10, 240));
const url = new URL('https://push2.eastmoney.com/api/qt/kamtbs.rtmin/get');
url.searchParams.set('fields1', 'f1,f2,f3,f4');
url.searchParams.set('fields2', 'f51,f52,f54,f56');
url.searchParams.set('ut', 'b2884a393a59ad64002292a3e90d46a5');
const resp = await fetch(url, { headers: { 'User-Agent': 'Mozilla/5.0' } });
if (!resp.ok) throw new CliError('HTTP_ERROR', `northbound failed: HTTP ${resp.status}`);
const data = await resp.json();
const key = (dir === 'south' || dir === 's') ? 's2n' : 'n2s';
/** @type {string[]} */
const rows = Array.isArray(data?.data?.[key]) ? data.data[key] : [];
if (rows.length === 0) throw new CliError('NO_DATA', `No ${key} data returned`);
// CSV fields per entry: "HH:MM,cumulative_net(万), minute_net(万), total_net(万)"
// Drop rows with '-' (after market close or before open). Convert 万元 → 亿元 for readability.
const valid = rows
.map((r) => r.split(','))
.filter((c) => c.length >= 4 && c[1] !== '-');
if (valid.length === 0) {
throw new CliError('NO_DATA', `${key} has no valid minute data yet (markets may not be open)`);
}
return valid.slice(-limit).map(([time, cum, min, total]) => ({
time,
cumulativeNetYi: +(Number(cum) / 10000).toFixed(4),
minuteNetYi: +(Number(min) / 10000).toFixed(4),View on GitHub (pinned to 49907e53dc)
Solutions
- Re-run the command after a short wait — transient 5xx and rate limits usually clear
- Check the HTTP status in the message: 403 suggests blocking/rate-limiting, 5xx suggests eastmoney-side trouble
- Slow down polling frequency and add backoff between calls
- Verify network/proxy access to push2.eastmoney.com (curl -I the URL)
- Check whether eastmoney changed the API path or ut token and update the URL in clis/eastmoney/northbound.js
Example fix
// before
const resp = await fetch(url, { headers: { 'User-Agent': 'Mozilla/5.0' } });
// after — retry with backoff on transient failures
const resp = await fetchWithRetry(url, { headers: { 'User-Agent': 'Mozilla/5.0' } }, { retries: 3 }); Defensive patterns
Strategy: retry
Validate before calling
// Preflight connectivity check
const probe = await fetch('https://push2.eastmoney.com/api/qt/kamtbs.rtmin/get?fields1=f1&fields2=f51&ut=b2884a393a59ad64002292a3e90d46a5', { headers: { 'User-Agent': 'Mozilla/5.0' } });
if (!probe.ok) throw new Error(`eastmoney unreachable: HTTP ${probe.status}`); Type guard
null
Try / catch
try {
await runNorthbound(args);
} catch (e) {
if (e.code === 'HTTP_ERROR' && /HTTP (5\d\d|429)/.test(e.message)) {
await sleep(backoff); return runNorthbound(args); // retry transient failures
}
if (e.code === 'HTTP_ERROR' && /HTTP 403/.test(e.message)) console.error('Blocked/rate-limited by eastmoney; reduce frequency or change network.');
else throw e;
} Prevention
- Add exponential backoff with jitter around fetch calls
- Poll at modest intervals (eastmoney rate-limits aggressive scraping)
- Monitor the specific status code: 403 = blocking, 5xx = server-side, 429 = rate limit
- Pin a realistic browser User-Agent and avoid datacenter IPs when possible
- Alert on persistent 403/404 which may mean the API path or ut token changed
When it happens
Trigger: Any non-2xx response from push2.eastmoney.com when calling the northbound command — e.g. 403 from bot detection / rate limiting, 404 if the endpoint path changes, 5xx from eastmoney server-side issues, or a captive proxy returning an error page status.
Common situations: Eastmoney blocking datacenter IPs or aggressively rate-limiting repeated polling; running from a region or network where the request is intercepted; eastmoney temporarily changing/removing the API path or the 'ut' token becoming invalid; transient 5xx during high-traffic market hours.
Understand the failure class
Background: "API error: {status}" and "HTTP 401/403/404/429/5xx" errors: non-2xx HTTP responses explained — this error's family across 27 libraries.
Related errors
- HTTP_ERROR
- 12306 queryByTrainNo returned HTTP ${resp.status}
- 12306 queryByTrainNo returned non-JSON body
- HTTP_ERROR
- eastmoney convertible failed: HTTP ${resp.status}
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/0f24573171adbcf8.
Report an issue: GitHub.