Set黑名单过滤核心优势是O(1)平均查找性能,适合高频实时拦截;预加载非法IP、域名等至Set,中间件中优先校验高区分度字段并短路判断,支持热更新与TTL临时拉黑。

用 Set 做黑名单过滤,核心优势是 O(1) 平均时间复杂度的查找性能,比数组 includes() 或 indexOf()(O(n))快得多,特别适合高频请求场景下的实时拦截。
构建高效黑名单 Set
把非法域名、IP、User-Agent 片段或请求 ID 预加载进 Set,确保唯一性且无排序开销:
const blacklist = new Set([ '192.168.0.100', 'bad-bot.example.com', 'curl/7.68.0', 'scanner-2024' ]);
- 初始化时直接传入数组,自动去重;动态添加用
blacklist.add('new-bad-ip') - 避免存对象或嵌套结构——
Set判等基于SameValueZero,字符串/数字最稳妥 - 若黑名单来自配置文件或数据库,建议启动时一次性载入,而非每次请求查库
在请求中间件中快速判断并拦截
以 Express 为例,在路由前检查关键字段是否命中黑名单:
app.use((req, res, next) => {
const ip = req.ip || req.connection.remoteAddress;
const host = req.headers.host;
const ua = req.get('User-Agent') || '';
if (
blacklist.has(ip) ||
blacklist.has(host) ||
blacklist.has(ua.substring(0, 20)) // 截取 UA 前缀防滥用
) {
return res.status(403).json({ error: 'Forbidden: blacklisted source' });
}
next();
});
- 优先检查高区分度字段(如 IP),短路后续判断提升响应速度
- 对模糊匹配需求(如 UA 包含关键词),可用
Array.from(blacklist).some(k => ua.includes(k)),但会退化为 O(n),应尽量用精确键设计 - 生产环境建议加日志记录拦截行为:
console.warn(`Blocked ${ip} on ${req.originalUrl}`)
支持运行时热更新黑名单
无需重启服务即可增删规则,适合应对突发攻击:
立即学习“Java免费学习笔记(深入)”;
- 提供管理接口(如
POST /admin/blacklist)接收新条目,调用blacklist.add(...items) - 删除用
blacklist.delete(item);清空用blacklist.clear() - 注意并发安全:Node.js 单线程下 Set 操作天然线程安全,但若搭配外部存储(如 Redis 同步),需额外协调一致性
进阶:结合 TTL 实现临时拉黑
Set 本身不支持过期,但可配合 Map 存储时间戳,定期清理:
const blacklistWithTTL = new Map(); // key: string, value: { expiresAt: number }
function addToBlacklist(key, ttlMs = 300_000) {
blacklistWithTTL.set(key, {
expiresAt: Date.now() + ttlMs
});
}
function isBlacklisted(key) {
const entry = blacklistWithTTL.get(key);
if (!entry) return false;
if (Date.now() > entry.expiresAt) {
blacklistWithTTL.delete(key);
return false;
}
return true;
}
- 适合封禁扫描器 IP 5 分钟、限制异常登录尝试等场景
- 可另起定时器每分钟清理过期项,或在
isBlacklisted中惰性清理


















