DIYgod/RSSHub · error · Error

Failed to fetch data from API

Error message

Failed to fetch data from API

What it means

Generic Error from a catch block wrapping got.post to the BNU (Beijing Normal University) faculty CMS API. Any thrown network/HTTP error is swallowed and re-thrown as this generic message, hiding the original cause. It signals the POST to fe.bnu.edu.cn's column listing endpoint could not complete.

Source

Thrown at lib/routes/bnu/fe.ts:41

async function handler(ctx) {
    const { category } = ctx.req.param();
    const apiUrl = 'https://fe.bnu.edu.cn/pc/cmscommon/nlist';
    let response;
    try {
        // 发送 POST 请求
        response = await got.post(apiUrl, {
            headers: {
                Accept: 'application/json, text/javascript, */*; q=0.01',
                'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
                Origin: 'https://fe.bnu.edu.cn',
                Referer: 'https://fe.bnu.edu.cn/pc/cms1info/list/1/18',
                'X-Requested-With': 'XMLHttpRequest',
            },
            body: `columnid=${category}&page=1`, // POST 数据
        });
    } catch {
        throw new Error('Failed to fetch data from API');
    }
    const jsonData = JSON.parse(response.body);
    // 检查返回的 code
    if (jsonData.code !== 0 || !jsonData.data) {
        throw new Error('Invalid API response');
    }

    const list = jsonData.data.map((item) => ({
        title: item.title,
        link: `https://fe.bnu.edu.cn/html/1/news/${item.htmlpath}/n${item.newsid}.html`,
        pubDate: parseDate(item.happendate, 'YYYY-MM-DD'),
    }));

    const out = await Promise.all(
        list.map((item) =>
            cache.tryGet(item.link, async () => {
                const response = await got(item.link);
                const $ = load(response.data);

View on GitHub (pinned to bed535e087)

Solutions

  1. Retry — campus CMS endpoints are intermittently flaky.
  2. Verify https://fe.bnu.edu.cn is reachable from the RSSHub host (curl the apiUrl with the same headers).
  3. If persistent, inspect the original error by temporarily logging it in the catch (the bare `catch {}` currently swallows it).
  4. Update the Referer/Origin/X-Requested-With headers if the CMS changed its CSRF checks.

Example fix

// before
} catch {
    throw new Error('Failed to fetch data from API');
}
// after (preserve the cause for diagnosis)
} catch (e) {
    throw new Error('Failed to fetch data from API: ' + (e instanceof Error ? e.message : String(e)));
}
Defensive patterns

Strategy: retry

Validate before calling

try {
    response = await got.post(apiUrl, { headers, body: `columnid=${category}&page=1` });
} catch (e) {
    throw new Error('Failed to fetch data from API: ' + (e instanceof Error ? e.message : String(e)));
}

Try / catch

// Wrap with a bounded retry for transient campus-network failures:
let response, lastErr;
for (let i = 0; i < 3; i++) {
    try { response = await got.post(apiUrl, { headers, body }); break; }
    catch (e) { lastErr = e; await delay(500 * (i + 1)); }
}
if (!response) throw new Error('Failed to fetch data from API: ' + lastErr);

Prevention

When it happens

Trigger: got.post to the apiUrl threw — connection reset, DNS failure, non-2xx status that got treats as an error, or a socket timeout. The catch (no binding) discards the original error and throws the generic string.

Common situations: The BNU site is down or rate-limiting; the server IP is blocked by the campus firewall; TLS/cert issues; the hardcoded Referer/Origin headers being rejected after a site change.

Related errors


AI-assisted analysis of DIYgod/RSSHub@bed535e087 (2026-08-12). Data as JSON: /api/errors/8b58207f5c4ebe71. Report an issue: GitHub.