使用mwn调用MediaWiki API时POST请求出现414 URI过长错误
我正在维护一个维基百科机器人,从mwbot框架迁移到mwn后遇到异常:调用POST请求检查用户封禁状态时,返回414 "URI too long"错误。
场景说明:通过MediaWiki Action API的list=blocks接口,用bkusers参数传入管道(|)分隔的500个用户名列表来批量查询封禁状态,相同逻辑在mwbot中可正常运行,排除服务器端问题。怀疑和mwn依赖的axios有关——之前用axios写网页抓取函数时频繁遇到"Package subpath './lib/defaults' is not defined by 'exports'"错误,已卸载axios改用node:https。
问题代码如下:
import { mwn } from "mwn"; (async () => { const mw: mwn = await mwn.init({ apiUrl: 'https://en.wikipedia.org/w/api.php', username: 'YourBotUsername', password: 'YourBotPassword', userAgent: 'myCoolToolName 1.0 ([[link to bot user page or tool documentation]])' }); interface DynamicObject { // eslint-disable-next-line @typescript-eslint/no-explicit-any [key: string]: any } interface ApiResponseListLogeventsItem { logid: number, ns: number, title: string, pageid: number, logpage: number, params: DynamicObject, type: string, action: string, user: string, anon?: boolean, timestamp: string, comment: string } // eslint-disable-next-line @typescript-eslint/no-empty-interface interface ApiResponseListLogevents extends Array<ApiResponseListLogeventsItem> {} // Get 500 (5000 if you're a bot) usernames from the latest logs of account creation const response = await mw.continuedQuery({ action: 'query', list: 'logevents', leprop: 'ids|title|timestamp', letype: 'newusers', lelimit: 'max', }, 1).then(res => res).catch(err => console.log(err.info)); if (!response) return; const resLgev: ApiResponseListLogevents = response.filter((obj: DynamicObject) => obj && obj.query && obj.query.logevents).map(obj => obj.query && obj.query.logevents).flat(); const users = resLgev.filter(obj => obj.title).map(obj => obj.title.replace(/^User:/, '')); console.log(users.length); // Check if any of the users is blocked const r = await mw.request({ // => Returns 414 'URI Too Long' although this is a POST request action: 'query', list: 'blocks', bklimit: 'max', bkusers: users.slice(0, 500).join('|'), // Pipe-separated list of users bkprop: 'user|timestamp|expiry|restrictions|flags', formatversion: '2' }, {method: 'POST'}).then(res => res).catch(err => console.log(err)); if (!r || !r.query || !r.query.blocks) return console.log('!'); console.log(r.query.blocks.length); })();
问题分析
mwn的mw.request()方法可能存在逻辑缺陷:即便指定了method: 'POST',仍默认将参数拼接在URL上而非放入请求体,导致长参数触发URI过长的414错误。另外,手动卸载axios后,mwn内部的请求逻辑可能未适配node:https的参数传递方式。
解决方案
1. 强制参数放入POST请求体
修改mw.request()的配置,明确将参数放在请求体中传递:
const r = await mw.request({ // 保留基础配置,确保action等标识正确 action: 'query', formatversion: '2' }, { method: 'POST', // 把所有查询参数放入data字段,强制通过请求体发送 data: { list: 'blocks', bklimit: 'max', bkusers: users.slice(0, 500).join('|'), bkprop: 'user|timestamp|expiry|restrictions|flags' } }).then(res => res).catch(err => console.log(err));
也可以查阅mwn官方文档,确认是否有usePostBody之类的内置配置项,一键启用POST体传参。
2. 修复axios依赖问题
mwn框架依赖axios实现请求功能,直接卸载会导致逻辑异常。之前的错误是axios版本不兼容导致的,建议安装兼容版本:
npm install axios@0.27.2
安装后重新运行项目,mwn会自动通过axios将POST参数放入请求体,避免URI过长问题。
3. 拆分批量请求作为兜底方案
如果上述方法无效,可将500个用户拆分为更小的批次(比如每100个一组),降低单请求的参数长度:
// 拆分用户列表为每100个一组 const userBatches = []; for (let i = 0; i < users.length; i += 100) { userBatches.push(users.slice(i, i + 100)); } // 批量请求并合并结果 const blockedUsers = []; for (const batch of userBatches) { const res = await mw.request({ action: 'query', list: 'blocks', bklimit: 'max', bkusers: batch.join('|'), bkprop: 'user|timestamp|expiry|restrictions|flags', formatversion: '2' }, {method: 'POST'}).catch(err => console.log(err)); if (res?.query?.blocks) { blockedUsers.push(...res.query.blocks); } } console.log(blockedUsers.length);
内容的提问来源于stack exchange,提问作者Dragoniez

