Azure App Service中Node.js未指定maxSockets调用HTTP端点遇ETIMEDOUT
解决Azure App Service中Node.js并发HTTP请求的Connect ETIMEDOUT问题
这个问题我之前在类似场景里碰到过——本质上是因为你没有限制HTTP Agent的并发连接数,加上Azure App Service的网络环境约束,导致一下子发起的大量连接被目标服务器或者Azure网络层限流,最终触发超时。
问题根源
你代码里创建的https.Agent用了默认配置,在Node.js v14及以后,maxSockets默认值是Infinity,这意味着当你一次性发起50个请求时,会同时尝试建立50个新的TCP连接。但目标服务器(比如microsoft.com)通常会对单IP的并发连接数做限制,再加上Azure App Service的出站连接有管控机制,超过阈值的连接就会被拒绝,最终出现Connect ETIMEDOUT。
解决方案
通过显式配置Agent的连接池参数,控制并发连接数并启用连接复用,就能解决这个问题:
- 配置带连接限制的HTTPS Agent
修改你的Agent创建代码,添加maxSockets、maxFreeSockets和keepAlive参数:
const fetch = require('node-fetch'); const https = require("https"); // 配置连接池参数,控制并发连接数并启用连接复用 const agent = new https.Agent({ maxSockets: 10, // 限制并发活跃连接数,可根据实际场景调整(比如10-20) maxFreeSockets: 10, // 空闲时保持的连接数,避免频繁创建销毁连接 keepAlive: true, // 开启长连接,复用已有连接 keepAliveMsecs: 30000 // 长连接空闲超时时间,默认1000ms,可适当延长 }); function doWork() { const works = []; for (let i = 0; i < 50; i++) { const wk = fetch('https://www.microsoft.com/robots.txt', { agent }) .then(res => res.text()) .then(body => console.log("OK", i)) .catch((err) => console.log("Error", i, err.message)); // 打印具体错误信息,方便排查 works.push(wk); } }
- 调整并发请求策略(可选)
如果50个请求必须全部发起,也可以考虑用分批处理的方式,比如每次只发10个请求,上一批完成后再发下一批,避免瞬间的连接压力:
async function doWorkBatch() { const batchSize = 10; for (let i = 0; i < 50; i += batchSize) { const batch = []; for (let j = i; j < Math.min(i + batchSize, 50); j++) { batch.push( fetch('https://www.microsoft.com/robots.txt', { agent }) .then(res => res.text()) .then(body => console.log("OK", j)) .catch(err => console.log("Error", j, err.message)) ); } await Promise.all(batch); // 等待当前批次完成后再处理下一批 } }
- 检查Azure App Service的资源限制
如果调整Agent参数后还是有问题,要检查你的App Service定价层:免费层(F1)和基本层(B1/B2/B3)的出站连接数有上限,如果你并发请求量确实很大,可能需要升级到标准层(S1/S2/S3),这类层级的出站连接限制更宽松。
原理说明
keepAlive启用后,Agent会保持已建立的TCP连接,后续请求可以复用这些连接,避免频繁创建新连接的开销和限制。maxSockets限制同时活跃的连接数,防止一次性发起过多连接触发目标服务器或Azure的限流。maxFreeSockets保证空闲时保留一定数量的连接,既不会浪费资源,也能快速响应新的请求。
内容的提问来源于stack exchange,提问作者Davide Icardi




