express - 一次限制一个请求
express - Limit a request to one at a time
我正在使用 express
构建一个应该在内部使用的 API。其中一个请求在服务器上触发了一个繁重的进程,应该 return 从中得到一个 CSV。此过程可能需要 10 多分钟。
为了不让服务器超载,我想限制对这个 API 的调用,因为进程没有终止,我们不能再次请求相同的 URL .
为此,我尝试使用具有以下配置的 express-rate-limit
:
new RateLimit({
windowMs: 30 * 60 * 1000, // 30 minutes
max: 1,
delayMs: 0, // disabled
message: 'Their is already a running execution of the request. You must wait for it to be finished before starting a new one.',
handler: function handler(req, res) {
logger.log('max request achieved');
logger.log(res);
},
});
但似乎每次都在 2 分钟后到达 'max request',即使我只开始一次。我怀疑如果没有得到任何答复,浏览器会在 2 分钟后重试请求,这可能吗?
我希望此请求没有任何 retry-strategy
并且达到 max request
的唯一方法是手动要求服务器连续执行此请求 2 次。
谢谢。
编辑
这是我的完整代码:
const app = express();
const port = process.env.API_PORT || 3000;
app.enable('trust proxy');
function haltOnTimedout(req, res, next) {
if (!req.timedout) { next(); }
}
app.use(timeout(30 * 60 * 1000)); // 30min
app.use(haltOnTimedout);
app.listen(port, () => {
logger.log(`Express server listening on port ${port}`);
});
// BILLING
const billingApiLimiter = new RateLimit({
windowMs: 30 * 60 * 1000, // 30 minutes
max: 1,
delayMs: 0, // disabled
message: 'Their is already a running execution of the request. You must wait for it to be finished before starting a new one.',
handler: function handler(req, res) {
logger.log('max request achieved');
},
});
app.use('/billing', billingApiLimiter);
app.use('/billing', BillingController);
还有我的代码 route
:
router.get('/billableElements', async (request, response) => {
logger.log('Route [billableElements] called');
const { startDate } = request.query;
const { endDate } = request.query;
try {
const configDoc = await metadataBucket.getAsync(process.env.BILLING_CONFIG_FILE || 'CONFIG_BILLING');
const billableElements = await getBillableElements(startDate, endDate, configDoc.value);
const csv = await produceCSV(billableElements);
logger.log('csv produced');
response.status(200).send(`${csv}`);
} catch (err) {
logger.error('An error occured while getting billable elements.', err);
response.status(500).send('An internal error occured.');
}
});
感谢这个 GitHub 问题,我找到了答案:https://github.com/expressjs/express/issues/2512。
TLDR:我添加了 request.connection.setTimeout(1000 * 60 * 30);
以避免每 2 分钟触发一次请求。
但考虑到我在问题中编写的代码,@Paul 的建议仍然值得考虑。
我正在使用 express
构建一个应该在内部使用的 API。其中一个请求在服务器上触发了一个繁重的进程,应该 return 从中得到一个 CSV。此过程可能需要 10 多分钟。
为了不让服务器超载,我想限制对这个 API 的调用,因为进程没有终止,我们不能再次请求相同的 URL .
为此,我尝试使用具有以下配置的 express-rate-limit
:
new RateLimit({
windowMs: 30 * 60 * 1000, // 30 minutes
max: 1,
delayMs: 0, // disabled
message: 'Their is already a running execution of the request. You must wait for it to be finished before starting a new one.',
handler: function handler(req, res) {
logger.log('max request achieved');
logger.log(res);
},
});
但似乎每次都在 2 分钟后到达 'max request',即使我只开始一次。我怀疑如果没有得到任何答复,浏览器会在 2 分钟后重试请求,这可能吗?
我希望此请求没有任何 retry-strategy
并且达到 max request
的唯一方法是手动要求服务器连续执行此请求 2 次。
谢谢。
编辑
这是我的完整代码:
const app = express();
const port = process.env.API_PORT || 3000;
app.enable('trust proxy');
function haltOnTimedout(req, res, next) {
if (!req.timedout) { next(); }
}
app.use(timeout(30 * 60 * 1000)); // 30min
app.use(haltOnTimedout);
app.listen(port, () => {
logger.log(`Express server listening on port ${port}`);
});
// BILLING
const billingApiLimiter = new RateLimit({
windowMs: 30 * 60 * 1000, // 30 minutes
max: 1,
delayMs: 0, // disabled
message: 'Their is already a running execution of the request. You must wait for it to be finished before starting a new one.',
handler: function handler(req, res) {
logger.log('max request achieved');
},
});
app.use('/billing', billingApiLimiter);
app.use('/billing', BillingController);
还有我的代码 route
:
router.get('/billableElements', async (request, response) => {
logger.log('Route [billableElements] called');
const { startDate } = request.query;
const { endDate } = request.query;
try {
const configDoc = await metadataBucket.getAsync(process.env.BILLING_CONFIG_FILE || 'CONFIG_BILLING');
const billableElements = await getBillableElements(startDate, endDate, configDoc.value);
const csv = await produceCSV(billableElements);
logger.log('csv produced');
response.status(200).send(`${csv}`);
} catch (err) {
logger.error('An error occured while getting billable elements.', err);
response.status(500).send('An internal error occured.');
}
});
感谢这个 GitHub 问题,我找到了答案:https://github.com/expressjs/express/issues/2512。
TLDR:我添加了 request.connection.setTimeout(1000 * 60 * 30);
以避免每 2 分钟触发一次请求。
但考虑到我在问题中编写的代码,@Paul 的建议仍然值得考虑。