给免费 AI 生图工具上线前,我先补了三道成本保护
给免费 AI 生图工具上线前,我先补了三道成本保护
给免费 AI 生图工具上线前,我先补了三道成本保护
最近给网站做了一个免费的 GPT Image 2 图片生成工具。用户不用注册,只需要输入提示词,就能生成一张固定 1:1、1K、low 质量的图片。
这个工具的目标很直接,用免费体验承接搜索流量,提高用户停留时间,再把需要更多尺寸、更高画质和历史记录的用户引导到专业版。
页面很快就能做出来,上线前的成本控制反而花了更多时间。免费生图每一次点击都会产生实际费用,如果只盯着页面体验,很容易在流量进来以后才发现预算和防刷都没有兜住。
进程内限流只能用于本地测试
最初的版本把生成次数、冷却时间、活动任务和每日消费都保存在 Node.js 进程内。单机本地测试没有问题,但服务一重启,所有记录都会清空。部署多个实例以后,每台机器还会各算各的额度,同一个用户可以在不同实例之间重复领取免费次数。
后来把这些状态统一放进 Redis,并用 Lua 脚本一次完成额度检查、冷却检查、并发占位和预算预占。Redis 官方文档明确说明脚本会原子执行,适合处理这种需要同时修改多个 Key 的状态判断。
现在同一个 IP 和设备在滚动 24 小时内最多成功生成 10 张,每次提交间隔 45 秒,每个用户只允许一个活动任务,全站免费通道并发暂定为 3。上游明确拒绝任务时会退回预算预占,任务已经被上游接收后则计入消费,避免用户关闭页面或不继续轮询时漏算成本。
真实 IP 不能直接相信浏览器请求头
匿名额度主要依赖 IP 和设备 Cookie。这里有一个很容易忽略的问题,浏览器可以自行提交 X-Forwarded-For、X-Real-IP 等请求头。如果应用直接读取这些值,攻击者只需要不断更换头部内容,就能绕过每个 IP 的限制。
这次的处理方式是让流量先经过 Cloudflare 和 Nginx。Nginx 只信任 Cloudflare 官方出口地址,根据 CF-Connecting-IP 恢复访客 IP,再覆盖传给 Node.js 的 X-Real-IP。同时由 Nginx 注入一段内部代理密钥,应用只有在密钥匹配时才接受这个 IP。