如何限制浏览器端应用的Discogs API请求频率?
解决Discogs API请求速率限制的本地限流方案
我来帮你搞定这个问题!之前我在做Discogs相关工具的时候也碰到过一模一样的速率限制问题,用任务队列+串行延迟请求的方式就能完美解决,而且不会像你之前用setInterval那样出现空跑循环的情况。
首先先明确Discogs的规则:免费未认证用户是60请求/分钟,认证用户可以提升到240请求/分钟。咱们的核心思路就是让请求严格按照这个频率串行发送,避免并发或者连续快速请求触发超限。
方案1:基于Fetch + Async/Await的队列限流(推荐,适配你的现有代码)
这个方案适配你已经写的getRelease函数,用任务队列来管理所有需要查询的ID,每次只处理一个请求,完成后等待固定间隔再处理下一个:
// 1. 定义全局任务队列,存放需要查询的release ID const releaseQueue = []; // 2. 根据Discogs限制设置请求间隔(免费用户60/分钟,留100ms缓冲用1100ms) const REQUEST_INTERVAL = 1100; // 3. 递归处理队列的核心函数 async function processQueue() { // 队列为空时终止递归 if (releaseQueue.length === 0) { console.log('所有Release查询完成!'); return; } // 取出队列第一个ID const currentId = releaseQueue.shift(); try { // 调用你的getRelease函数获取数据 const parsedData = await getRelease(currentId); // 这里写处理CSV的逻辑,比如把parsedData存入数组或写入文件 console.log(`成功处理Release ${currentId}`); } catch (error) { console.error(`处理Release ${currentId}失败:`, error.message); // 可选:如果请求失败,把ID放回队列末尾重试 // releaseQueue.push(currentId); } // 等待指定间隔后,继续处理下一个请求 setTimeout(processQueue, REQUEST_INTERVAL); } // 4. 你的原有getRelease函数,优化错误处理(新增429超限处理) function getRelease(id) { return fetch(`https://api.discogs.com/releases/${id}`, { headers: { 'User-Agent': 'CSV for Discogs/0.1', } }) .then(response => { // 处理速率超限(429状态码),读取官方返回的重试等待时间 if (response.status === 429) { const retryAfter = parseInt(response.headers.get('Retry-After')) || 10; console.log(`触发速率限制,将在${retryAfter}秒后重试`); // 等待指定时间后重新发起请求 return new Promise(resolve => setTimeout(resolve, retryAfter * 1000)) .then(() => getRelease(id)); } // 处理其他错误状态 if (!response.ok) { throw new Error(`请求失败,状态码: ${response.status}`); } return response.json(); }) .then(parseReleaseData); } // 5. 使用方式:把输入文件的ID数组加入队列,启动处理 // 假设你从输入文件读取到的ID数组是inputIds const inputIds = [12345, 67890, ...]; // 你的30+个Release ID releaseQueue.push(...inputIds); // 启动队列处理 processQueue();
方案2:基于XMLHttpRequest的队列限流
如果你的代码还在使用XMLHttpRequest,也可以用类似的队列思路,通过请求完成的回调来触发下一个请求:
const releaseQueue = []; const REQUEST_INTERVAL = 1100; function processQueue() { if (releaseQueue.length === 0) { console.log('所有请求处理完成'); return; } const currentId = releaseQueue.shift(); const request = new XMLHttpRequest(); request.open('GET', `https://api.discogs.com/releases/${currentId}`); // 必须设置User-Agent,Discogs强制要求,否则会被拒绝请求 request.setRequestHeader('User-Agent', 'CSV for Discogs/0.1'); request.onload = function() { if (request.status >= 200 && request.status < 300) { const data = JSON.parse(request.responseText); const parsedData = parseReleaseData(data); console.log(`成功处理Release ${currentId}`); } else { console.error(`处理Release ${currentId}失败,状态码: ${request.status}`); // 可选:失败重试 // releaseQueue.push(currentId); } // 当前请求完成后,延迟启动下一个 setTimeout(processQueue, REQUEST_INTERVAL); }; request.onerror = function() { console.error(`请求Release ${currentId}时发生网络错误`); setTimeout(processQueue, REQUEST_INTERVAL); }; request.send(); } // 使用方式 const inputIds = [12345, 67890, ...]; releaseQueue.push(...inputIds); processQueue();
关键注意点
- 必须设置User-Agent:Discogs API强制要求所有请求携带合法的User-Agent,否则会直接拒绝请求,你的XMLHttpRequest代码片段里没加,一定要补上!
- 灵活调整间隔:如果你用了Discogs认证(个人访问令牌或OAuth),速率限制提升到240请求/分钟,这时候可以把间隔改成260ms左右(留缓冲)。
- 错误重试:对于429错误或者网络错误,可以把失败的ID放回队列末尾重试,避免遗漏数据。
内容的提问来源于stack exchange,提问作者double-happiness
相关产品推荐
相关产品推荐

