我需要通过HTTP检查本地服务器上大约300.000个URL的可用性。这些文件不在本地文件系统中,而是在键值存储中,目标是检查每个需要访问这些文件的系统是否都可以使用vial HTTP。
为此,我会使用HTTP HEAD请求为每个找到的文件返回HTTP 200,为每个找不到的文件返回404.
问题是,如果我一次做太多请求,我会受到nginx或本地代理的限制,因此无法确定文件是否真的可以访问。
我查找文件可用性的方法如下:
...
const request = require('request'); // Using the request lib.
...
const checkEntity = entity => {
logger.debug("HTTP HEAD ", entity);
return request({ method: "HEAD", uri: entity.url })
.then(result => {
logger.debug("Successfully retrieved file: " + entity.url);
entity.valid = result != undefined;
})
.catch(err => {
logger.debug("Failed to retrieve file.", err);
entity.valid = false;
});
}
如果我多次调用此函数,事情会按预期工作。当试图在递归承诺中运行它时,我很快超过了最大堆栈。为每个调用设置一个承诺会导致内存使用过多。
怎么能解决这个问题?
答案 0 :(得分:0)
这个问题可以通过以下步骤解决:
entities
(所有需要检查的网址)。N
,您可以根据服务器状态定义合理的数字。N
个HTTP请求。entity
并发送新请求。要在请求完成后收到通知,您可以在checkEntity
函数中添加回调参数。这样,最大HTTP请求数永远不会超过N
。
以下是基于代码段的伪代码示例:
let allEntities = [...]; // 300000 URLs
let finishedEntities = [];
const request = require('request'); // Using the request lib.
...
const checkEntity = function(entity, callback) {
logger.debug("HTTP HEAD ", entity);
return request({ method: "HEAD", uri: entity.url })
.then(result => {
logger.debug("Successfully retrieved file: " + entity.url);
entity.valid = result != undefined;
callback(entity);
})
.catch(err => {
logger.debug("Failed to retrieve file.", err);
entity.valid = false;
callback(entity)
});
}
function checkEntityCallback(entity) {
finishedEntities.push(entity);
let newEntity = allEntities.shift();
if (newEntity) {
checkEntity(allEntities.shift(), checkEntityCallback);
}
}
for (let i=0; i<10; i++) {
checkEntity(allEntities.shift(), checkEntityCallback);
}
为了便于理解,您可以更改request
的使用并删除所有承诺内容:
const checkEntity = function(entity, callback) {
logger.debug("HTTP HEAD ", entity);
request({ method: "HEAD", uri: entity.url }, function(error, response, body) {
if (error) {
logger.debug("Failed to retrieve file.", error);
entity.valid = false;
callback(entity);
return;
}
logger.debug("Successfully retrieved file: " + entity.url);
entity.valid = body != undefined;
callback(entity);
});
}