{"record":{"id":"c3e7ce3b94dc8dce","repo":"DIYgod/RSSHub","slug":"json-stringify-resp-d","errorCode":null,"errorMessage":"文章列表获取失败，可能是被临时限制了访问，请稍后重试\n${JSON.stringify(resp.data)}","messagePattern":"文章列表获取失败，可能是被临时限制了访问，请稍后重试\n(.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"lib/routes/gdut/oa-news.ts","lineNumber":108,"sourceCode":"    const type = typeMap[typeParam];\n\n    // 获取cookie\n    const cookieJar = new CookieJar();\n    await got(site + '/ggIP.do?method=portalSeachMore&subject=&departmentName=&newsType=&startDate=&endDate=', {\n        cookieJar,\n    });\n\n    // 获取文章列表\n    const listUrl = '/ajax.do?method=ajaxAction&managerName=ggManager&rnd=1';\n    const resp = await got.post(site + listUrl, {\n        cookieJar,\n        form: {\n            managerMethod: 'kkFindListDatas',\n            arguments: getArg(type),\n        },\n    });\n    if (!resp.data.data) {\n        throw new Error('文章列表获取失败，可能是被临时限制了访问，请稍后重试\\n' + JSON.stringify(resp.data));\n    }\n\n    // 构造文章数组\n    const articles: Array<DataItem & { link: string }> = resp.data.data.map((item): DataItem & { link: string } => ({\n        title: item.title,\n        guid: item.id,\n        link: site + '/newsData.do?method=newsView&newsId=' + item.id,\n        pubDate: timezone(parseDate(item.publishDate), 8),\n        author: item.publishUserDepart,\n        category: item.typeName,\n    }));\n\n    const results = await pMap(\n        articles,\n        async (data) => {\n            const link = data.link;\n            data.description = (await cache.tryGet(link, async () => {\n                // 获取数据","sourceCodeStart":90,"sourceCodeEnd":126,"githubUrl":"https://github.com/DIYgod/RSSHub/blob/bed535e0879dc71c5aff6f1e7bd1ac21ede40115/lib/routes/gdut/oa-news.ts#L90-L126","documentation":"Thrown by the GDUT OA news route after a POST to the Seeyon AJAX endpoint (/ajax.do?method=ajaxAction&managerName=ggManager) when the response body lacks a 'data' property (resp.data.data is falsy). The error message appends JSON.stringify(resp.data) for diagnostic purposes. The route documentation notes the school may restrict access from non-campus IPs.","triggerScenarios":"The Seeyon OA system returns a JSON response without the expected 'data' array — typically an error object, empty object, or login redirect payload. This happens when the server IP-blocks non-campus traffic, when the CookieJar session is invalid/expired, or when the form arguments are malformed.","commonSituations":"Self-hosting RSSHub outside the GDUT campus network (the description explicitly warns IP restrictions apply for department, academy, notice, and announcement types); the CookieJar initialization request (ggIP.do) succeeded but the subsequent POST was rejected; transient server-side throttling.","solutions":["Run RSSHub from within the GDUT campus network, or use a campus-network VPN/proxy, as the description warns","Retry after a few minutes in case of transient rate-limiting","Inspect the JSON in the error message — if it contains a login redirect or error, the session cookie logic may need updating","Verify the getArg() function produces valid arguments for the Seeyon AJAX contract"],"exampleFix":"// before\nif (!resp.data.data) {\n    throw new Error('文章列表获取失败，可能是被临时限制了访问，请稍后重试\\n' + JSON.stringify(resp.data));\n}\n\n// after (include the HTTP status and a structured hint)\nif (!resp.data.data) {\n    throw new Error(`Article list fetch failed (likely IP restriction or rate limit). HTTP ${resp.statusCode}. Response: ${JSON.stringify(resp.data)}`);\n}","handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"// The error is thrown after the API call. Wrap in retry with backoff:\nconst MAX_RETRIES = 3;\nlet lastError;\nfor (let i = 0; i < MAX_RETRIES; i++) {\n    try {\n        const resp = await got.post(site + listUrl, { cookieJar, form: {...} });\n        if (resp.data.data) {\n            // success\n            break;\n        }\n        throw new Error('No data in response');\n    } catch (e) {\n        lastError = e;\n        await new Promise(r => setTimeout(r, (i + 1) * 5000));\n    }\n}","preventionTips":["Run RSSHub from within the GDUT campus network for this route","Implement retry with exponential backoff for transient IP restrictions","Log the full response body to diagnose API contract changes","Share a campus-network proxy among multiple RSSHub instances"],"tags":["network","api","ip-restriction","rate-limit","anti-crawler"],"backgroundTag":null,"analyzedSha":"bed535e0879dc71c5aff6f1e7bd1ac21ede40115","analyzedAt":"2026-08-12T19:29:35.364Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}