{"record":{"id":"0a31b2731ba314d2","repo":"DIYgod/RSSHub","slug":"no-article-body","errorCode":null,"errorMessage":"No article body","messagePattern":"No article body","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"warning","filePath":"lib/routes/gdufs/xwxy/index.ts","lineNumber":85,"sourceCode":"                let isInternal = false;\n                try {\n                    const u = new URL(item.link);\n                    isInternal = u.hostname.endsWith('gdufs.edu.cn');\n                } catch {\n                    // ignore malformed URL\n                }\n\n                if (!isInternal) {\n                    return {\n                        ...item,\n                        description: '',\n                        author: '',\n                    };\n                }\n\n                const articleResponse = await got(item.link);\n                if (!articleResponse.body) {\n                    throw new Error('No article body');\n                }\n                const $$ = load(articleResponse.body);\n                // 使用 .v_news_content 选择器\n                const $content = $$('.v_news_content');\n\n                // 绝对化 img/src 与 a/href\n                $content.find('img, a').each((_, el) => {\n                    const $el = $$(el);\n                    const attrs = ['src', 'href'];\n                    for (const attr of attrs) {\n                        const v = $el.attr(attr);\n                        if (v && !v.startsWith('http')) {\n                            try {\n                                $el.attr(attr, new URL(v, item.link).href);\n                            } catch {\n                                // ignore malformed url\n                            }\n                        }","sourceCodeStart":67,"sourceCodeEnd":103,"githubUrl":"https://github.com/DIYgod/RSSHub/blob/bed535e0879dc71c5aff6f1e7bd1ac21ede40115/lib/routes/gdufs/xwxy/index.ts#L67-L103","documentation":"After the listing is parsed, each internal article link is fetched and its body is required to extract the .v_news_content container. If articleResponse.body is falsy, the route throws 'No article body'. This is the per-article version of the listing-body check and runs inside a Promise.all, so one bad article can fail the whole feed.","triggerScenarios":"A specific article URL returns an empty body (server hiccup, the article was removed between listing and detail fetch, or a login/redirect interstitial), while the listing itself was fine. Because the fetch is in a tight loop, any single failing article surfaces this error.","commonSituations":"Articles being taken offline between the list fetch and the detail fetch; university servers intermittently dropping connections; rate limiting causing truncated responses.","solutions":["Wrap the per-article fetch so one empty body returns a partial item (empty description) instead of failing the entire feed.","Retry the individual article fetch once before giving up.","Cache successful article fetches so transient failures do not recur.","Verify the article link is absolute/correct (relative links resolved wrong can hit a dead URL)."],"exampleFix":"// before\nconst articleResponse = await got(item.link);\nif (!articleResponse.body) {\n    throw new Error('No article body');\n}\n\n// after\nconst articleResponse = await got(item.link);\nif (!articleResponse.body) {\n    logger.warn(`Empty body for ${item.link}, returning partial item`);\n    return { ...item, description: '', author: '' };\n}","handlingStrategy":"fallback","validationCode":"// pre-flight is per-article inside a loop; instead guard the fetch result","typeGuard":"const hasArticleBody = (r: { body: unknown }): boolean => !!r.body;","tryCatchPattern":"const articleResponse = await got(item.link).catch(() => null);\nif (!articleResponse?.body) {\n  return { ...item, description: '', author: '' }; // graceful degradation\n}","preventionTips":["Degrade gracefully: return a partial item instead of failing the whole feed.\nRetry individual article fetches once.\nCache successful fetches to avoid re-hitting flaky servers.","Verify article links are absolute before fetching."],"tags":["network","scraping","empty-response","resilience"],"backgroundTag":null,"analyzedSha":"bed535e0879dc71c5aff6f1e7bd1ac21ede40115","analyzedAt":"2026-08-12T19:29:35.364Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}